]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/iD/iD.js
Merge remote-tracking branch 'upstream/pull/2931' 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         var geojsonRewind = rewind;
26340
26341         function rewind(gj, outer) {
26342           var type = gj && gj.type,
26343               i;
26344
26345           if (type === 'FeatureCollection') {
26346             for (i = 0; i < gj.features.length; i++) {
26347               rewind(gj.features[i], outer);
26348             }
26349           } else if (type === 'GeometryCollection') {
26350             for (i = 0; i < gj.geometries.length; i++) {
26351               rewind(gj.geometries[i], outer);
26352             }
26353           } else if (type === 'Feature') {
26354             rewind(gj.geometry, outer);
26355           } else if (type === 'Polygon') {
26356             rewindRings(gj.coordinates, outer);
26357           } else if (type === 'MultiPolygon') {
26358             for (i = 0; i < gj.coordinates.length; i++) {
26359               rewindRings(gj.coordinates[i], outer);
26360             }
26361           }
26362
26363           return gj;
26364         }
26365
26366         function rewindRings(rings, outer) {
26367           if (rings.length === 0) return;
26368           rewindRing(rings[0], outer);
26369
26370           for (var i = 1; i < rings.length; i++) {
26371             rewindRing(rings[i], !outer);
26372           }
26373         }
26374
26375         function rewindRing(ring, dir) {
26376           var area = 0;
26377
26378           for (var i = 0, len = ring.length, j = len - 1; i < len; j = i++) {
26379             area += (ring[i][0] - ring[j][0]) * (ring[j][1] + ring[i][1]);
26380           }
26381
26382           if (area >= 0 !== !!dir) ring.reverse();
26383         }
26384
26385         function actionExtract(entityID) {
26386           var extractedNodeID;
26387
26388           var action = function action(graph) {
26389             var entity = graph.entity(entityID);
26390
26391             if (entity.type === 'node') {
26392               return extractFromNode(entity, graph);
26393             }
26394
26395             return extractFromWayOrRelation(entity, graph);
26396           };
26397
26398           function extractFromNode(node, graph) {
26399             extractedNodeID = node.id; // Create a new node to replace the one we will detach
26400
26401             var replacement = osmNode({
26402               loc: node.loc
26403             });
26404             graph = graph.replace(replacement); // Process each way in turn, updating the graph as we go
26405
26406             graph = graph.parentWays(node).reduce(function (accGraph, parentWay) {
26407               return accGraph.replace(parentWay.replaceNode(entityID, replacement.id));
26408             }, graph); // Process any relations too
26409
26410             return graph.parentRelations(node).reduce(function (accGraph, parentRel) {
26411               return accGraph.replace(parentRel.replaceMember(node, replacement));
26412             }, graph);
26413           }
26414
26415           function extractFromWayOrRelation(entity, graph) {
26416             var fromGeometry = entity.geometry(graph);
26417             var keysToCopyAndRetain = ['source', 'wheelchair'];
26418             var keysToRetain = ['area'];
26419             var buildingKeysToRetain = ['architect', 'building', 'height', 'layer']; // d3_geoCentroid is wrong for counterclockwise-wound polygons, so wind them clockwise
26420
26421             var extractedLoc = d3_geoCentroid(geojsonRewind(Object.assign({}, entity.asGeoJSON(graph)), true));
26422
26423             if (!extractedLoc || !isFinite(extractedLoc[0]) || !isFinite(extractedLoc[1])) {
26424               extractedLoc = entity.extent(graph).center();
26425             }
26426
26427             var indoorAreaValues = {
26428               area: true,
26429               corridor: true,
26430               elevator: true,
26431               level: true,
26432               room: true
26433             };
26434             var isBuilding = entity.tags.building && entity.tags.building !== 'no' || entity.tags['building:part'] && entity.tags['building:part'] !== 'no';
26435             var isIndoorArea = fromGeometry === 'area' && entity.tags.indoor && indoorAreaValues[entity.tags.indoor];
26436             var entityTags = Object.assign({}, entity.tags); // shallow copy
26437
26438             var pointTags = {};
26439
26440             for (var key in entityTags) {
26441               if (entity.type === 'relation' && key === 'type') {
26442                 continue;
26443               }
26444
26445               if (keysToRetain.indexOf(key) !== -1) {
26446                 continue;
26447               }
26448
26449               if (isBuilding) {
26450                 // don't transfer building-related tags
26451                 if (buildingKeysToRetain.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
26452               } // leave `indoor` tag on the area
26453
26454
26455               if (isIndoorArea && key === 'indoor') {
26456                 continue;
26457               } // copy the tag from the entity to the point
26458
26459
26460               pointTags[key] = entityTags[key]; // leave addresses and some other tags so they're on both features
26461
26462               if (keysToCopyAndRetain.indexOf(key) !== -1 || key.match(/^addr:.{1,}/)) {
26463                 continue;
26464               } else if (isIndoorArea && key === 'level') {
26465                 // leave `level` on both features
26466                 continue;
26467               } // remove the tag from the entity
26468
26469
26470               delete entityTags[key];
26471             }
26472
26473             if (!isBuilding && !isIndoorArea && fromGeometry === 'area') {
26474               // ensure that areas keep area geometry
26475               entityTags.area = 'yes';
26476             }
26477
26478             var replacement = osmNode({
26479               loc: extractedLoc,
26480               tags: pointTags
26481             });
26482             graph = graph.replace(replacement);
26483             extractedNodeID = replacement.id;
26484             return graph.replace(entity.update({
26485               tags: entityTags
26486             }));
26487           }
26488
26489           action.getExtractedNodeID = function () {
26490             return extractedNodeID;
26491           };
26492
26493           return action;
26494         }
26495
26496         //
26497         // This is the inverse of `iD.actionSplit`.
26498         //
26499         // Reference:
26500         //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
26501         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
26502         //
26503
26504         function actionJoin(ids) {
26505           function groupEntitiesByGeometry(graph) {
26506             var entities = ids.map(function (id) {
26507               return graph.entity(id);
26508             });
26509             return Object.assign({
26510               line: []
26511             }, utilArrayGroupBy(entities, function (entity) {
26512               return entity.geometry(graph);
26513             }));
26514           }
26515
26516           var action = function action(graph) {
26517             var ways = ids.map(graph.entity, graph);
26518             var survivorID = ways[0].id; // if any of the ways are sided (e.g. coastline, cliff, kerb)
26519             // sort them first so they establish the overall order - #6033
26520
26521             ways.sort(function (a, b) {
26522               var aSided = a.isSided();
26523               var bSided = b.isSided();
26524               return aSided && !bSided ? -1 : bSided && !aSided ? 1 : 0;
26525             }); // Prefer to keep an existing way.
26526
26527             for (var i = 0; i < ways.length; i++) {
26528               if (!ways[i].isNew()) {
26529                 survivorID = ways[i].id;
26530                 break;
26531               }
26532             }
26533
26534             var sequences = osmJoinWays(ways, graph);
26535             var joined = sequences[0]; // We might need to reverse some of these ways before joining them.  #4688
26536             // `joined.actions` property will contain any actions we need to apply.
26537
26538             graph = sequences.actions.reduce(function (g, action) {
26539               return action(g);
26540             }, graph);
26541             var survivor = graph.entity(survivorID);
26542             survivor = survivor.update({
26543               nodes: joined.nodes.map(function (n) {
26544                 return n.id;
26545               })
26546             });
26547             graph = graph.replace(survivor);
26548             joined.forEach(function (way) {
26549               if (way.id === survivorID) return;
26550               graph.parentRelations(way).forEach(function (parent) {
26551                 graph = graph.replace(parent.replaceMember(way, survivor));
26552               });
26553               survivor = survivor.mergeTags(way.tags);
26554               graph = graph.replace(survivor);
26555               graph = actionDeleteWay(way.id)(graph);
26556             }); // Finds if the join created a single-member multipolygon,
26557             // and if so turns it into a basic area instead
26558
26559             function checkForSimpleMultipolygon() {
26560               if (!survivor.isClosed()) return;
26561               var multipolygons = graph.parentMultipolygons(survivor).filter(function (multipolygon) {
26562                 // find multipolygons where the survivor is the only member
26563                 return multipolygon.members.length === 1;
26564               }); // skip if this is the single member of multiple multipolygons
26565
26566               if (multipolygons.length !== 1) return;
26567               var multipolygon = multipolygons[0];
26568
26569               for (var key in survivor.tags) {
26570                 if (multipolygon.tags[key] && // don't collapse if tags cannot be cleanly merged
26571                 multipolygon.tags[key] !== survivor.tags[key]) return;
26572               }
26573
26574               survivor = survivor.mergeTags(multipolygon.tags);
26575               graph = graph.replace(survivor);
26576               graph = actionDeleteRelation(multipolygon.id, true
26577               /* allow untagged members */
26578               )(graph);
26579               var tags = Object.assign({}, survivor.tags);
26580
26581               if (survivor.geometry(graph) !== 'area') {
26582                 // ensure the feature persists as an area
26583                 tags.area = 'yes';
26584               }
26585
26586               delete tags.type; // remove type=multipolygon
26587
26588               survivor = survivor.update({
26589                 tags: tags
26590               });
26591               graph = graph.replace(survivor);
26592             }
26593
26594             checkForSimpleMultipolygon();
26595             return graph;
26596           }; // Returns the number of nodes the resultant way is expected to have
26597
26598
26599           action.resultingWayNodesLength = function (graph) {
26600             return ids.reduce(function (count, id) {
26601               return count + graph.entity(id).nodes.length;
26602             }, 0) - ids.length - 1;
26603           };
26604
26605           action.disabled = function (graph) {
26606             var geometries = groupEntitiesByGeometry(graph);
26607
26608             if (ids.length < 2 || ids.length !== geometries.line.length) {
26609               return 'not_eligible';
26610             }
26611
26612             var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
26613
26614             if (joined.length > 1) {
26615               return 'not_adjacent';
26616             } // Loop through all combinations of path-pairs
26617             // to check potential intersections between all pairs
26618
26619
26620             for (var i = 0; i < ids.length - 1; i++) {
26621               for (var j = i + 1; j < ids.length; j++) {
26622                 var path1 = graph.childNodes(graph.entity(ids[i])).map(function (e) {
26623                   return e.loc;
26624                 });
26625                 var path2 = graph.childNodes(graph.entity(ids[j])).map(function (e) {
26626                   return e.loc;
26627                 });
26628                 var intersections = geoPathIntersections(path1, path2); // Check if intersections are just nodes lying on top of
26629                 // each other/the line, as opposed to crossing it
26630
26631                 var common = utilArrayIntersection(joined[0].nodes.map(function (n) {
26632                   return n.loc.toString();
26633                 }), intersections.map(function (n) {
26634                   return n.toString();
26635                 }));
26636
26637                 if (common.length !== intersections.length) {
26638                   return 'paths_intersect';
26639                 }
26640               }
26641             }
26642
26643             var nodeIds = joined[0].nodes.map(function (n) {
26644               return n.id;
26645             }).slice(1, -1);
26646             var relation;
26647             var tags = {};
26648             var conflicting = false;
26649             joined[0].forEach(function (way) {
26650               var parents = graph.parentRelations(way);
26651               parents.forEach(function (parent) {
26652                 if (parent.isRestriction() && parent.members.some(function (m) {
26653                   return nodeIds.indexOf(m.id) >= 0;
26654                 })) {
26655                   relation = parent;
26656                 }
26657               });
26658
26659               for (var k in way.tags) {
26660                 if (!(k in tags)) {
26661                   tags[k] = way.tags[k];
26662                 } else if (tags[k] && osmIsInterestingTag(k) && tags[k] !== way.tags[k]) {
26663                   conflicting = true;
26664                 }
26665               }
26666             });
26667
26668             if (relation) {
26669               return 'restriction';
26670             }
26671
26672             if (conflicting) {
26673               return 'conflicting_tags';
26674             }
26675           };
26676
26677           return action;
26678         }
26679
26680         function actionMerge(ids) {
26681           function groupEntitiesByGeometry(graph) {
26682             var entities = ids.map(function (id) {
26683               return graph.entity(id);
26684             });
26685             return Object.assign({
26686               point: [],
26687               area: [],
26688               line: [],
26689               relation: []
26690             }, utilArrayGroupBy(entities, function (entity) {
26691               return entity.geometry(graph);
26692             }));
26693           }
26694
26695           var action = function action(graph) {
26696             var geometries = groupEntitiesByGeometry(graph);
26697             var target = geometries.area[0] || geometries.line[0];
26698             var points = geometries.point;
26699             points.forEach(function (point) {
26700               target = target.mergeTags(point.tags);
26701               graph = graph.replace(target);
26702               graph.parentRelations(point).forEach(function (parent) {
26703                 graph = graph.replace(parent.replaceMember(point, target));
26704               });
26705               var nodes = utilArrayUniq(graph.childNodes(target));
26706               var removeNode = point;
26707
26708               for (var i = 0; i < nodes.length; i++) {
26709                 var node = nodes[i];
26710
26711                 if (graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags()) {
26712                   continue;
26713                 } // Found an uninteresting child node on the target way.
26714                 // Move orig point into its place to preserve point's history. #3683
26715
26716
26717                 graph = graph.replace(point.update({
26718                   tags: {},
26719                   loc: node.loc
26720                 }));
26721                 target = target.replaceNode(node.id, point.id);
26722                 graph = graph.replace(target);
26723                 removeNode = node;
26724                 break;
26725               }
26726
26727               graph = graph.remove(removeNode);
26728             });
26729
26730             if (target.tags.area === 'yes') {
26731               var tags = Object.assign({}, target.tags); // shallow copy
26732
26733               delete tags.area;
26734
26735               if (osmTagSuggestingArea(tags)) {
26736                 // remove the `area` tag if area geometry is now implied - #3851
26737                 target = target.update({
26738                   tags: tags
26739                 });
26740                 graph = graph.replace(target);
26741               }
26742             }
26743
26744             return graph;
26745           };
26746
26747           action.disabled = function (graph) {
26748             var geometries = groupEntitiesByGeometry(graph);
26749
26750             if (geometries.point.length === 0 || geometries.area.length + geometries.line.length !== 1 || geometries.relation.length !== 0) {
26751               return 'not_eligible';
26752             }
26753           };
26754
26755           return action;
26756         }
26757
26758         //
26759         // 1. move all the nodes to a common location
26760         // 2. `actionConnect` them
26761
26762         function actionMergeNodes(nodeIDs, loc) {
26763           // If there is a single "interesting" node, use that as the location.
26764           // Otherwise return the average location of all the nodes.
26765           function chooseLoc(graph) {
26766             if (!nodeIDs.length) return null;
26767             var sum = [0, 0];
26768             var interestingCount = 0;
26769             var interestingLoc;
26770
26771             for (var i = 0; i < nodeIDs.length; i++) {
26772               var node = graph.entity(nodeIDs[i]);
26773
26774               if (node.hasInterestingTags()) {
26775                 interestingLoc = ++interestingCount === 1 ? node.loc : null;
26776               }
26777
26778               sum = geoVecAdd(sum, node.loc);
26779             }
26780
26781             return interestingLoc || geoVecScale(sum, 1 / nodeIDs.length);
26782           }
26783
26784           var action = function action(graph) {
26785             if (nodeIDs.length < 2) return graph;
26786             var toLoc = loc;
26787
26788             if (!toLoc) {
26789               toLoc = chooseLoc(graph);
26790             }
26791
26792             for (var i = 0; i < nodeIDs.length; i++) {
26793               var node = graph.entity(nodeIDs[i]);
26794
26795               if (node.loc !== toLoc) {
26796                 graph = graph.replace(node.move(toLoc));
26797               }
26798             }
26799
26800             return actionConnect(nodeIDs)(graph);
26801           };
26802
26803           action.disabled = function (graph) {
26804             if (nodeIDs.length < 2) return 'not_eligible';
26805
26806             for (var i = 0; i < nodeIDs.length; i++) {
26807               var entity = graph.entity(nodeIDs[i]);
26808               if (entity.type !== 'node') return 'not_eligible';
26809             }
26810
26811             return actionConnect(nodeIDs).disabled(graph);
26812           };
26813
26814           return action;
26815         }
26816
26817         function osmChangeset() {
26818           if (!(this instanceof osmChangeset)) {
26819             return new osmChangeset().initialize(arguments);
26820           } else if (arguments.length) {
26821             this.initialize(arguments);
26822           }
26823         }
26824         osmEntity.changeset = osmChangeset;
26825         osmChangeset.prototype = Object.create(osmEntity.prototype);
26826         Object.assign(osmChangeset.prototype, {
26827           type: 'changeset',
26828           extent: function extent() {
26829             return new geoExtent();
26830           },
26831           geometry: function geometry() {
26832             return 'changeset';
26833           },
26834           asJXON: function asJXON() {
26835             return {
26836               osm: {
26837                 changeset: {
26838                   tag: Object.keys(this.tags).map(function (k) {
26839                     return {
26840                       '@k': k,
26841                       '@v': this.tags[k]
26842                     };
26843                   }, this),
26844                   '@version': 0.6,
26845                   '@generator': 'iD'
26846                 }
26847               }
26848             };
26849           },
26850           // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
26851           // XML. Returns a string.
26852           osmChangeJXON: function osmChangeJXON(changes) {
26853             var changeset_id = this.id;
26854
26855             function nest(x, order) {
26856               var groups = {};
26857
26858               for (var i = 0; i < x.length; i++) {
26859                 var tagName = Object.keys(x[i])[0];
26860                 if (!groups[tagName]) groups[tagName] = [];
26861                 groups[tagName].push(x[i][tagName]);
26862               }
26863
26864               var ordered = {};
26865               order.forEach(function (o) {
26866                 if (groups[o]) ordered[o] = groups[o];
26867               });
26868               return ordered;
26869             } // sort relations in a changeset by dependencies
26870
26871
26872             function sort(changes) {
26873               // find a referenced relation in the current changeset
26874               function resolve(item) {
26875                 return relations.find(function (relation) {
26876                   return item.keyAttributes.type === 'relation' && item.keyAttributes.ref === relation['@id'];
26877                 });
26878               } // a new item is an item that has not been already processed
26879
26880
26881               function isNew(item) {
26882                 return !sorted[item['@id']] && !processing.find(function (proc) {
26883                   return proc['@id'] === item['@id'];
26884                 });
26885               }
26886
26887               var processing = [];
26888               var sorted = {};
26889               var relations = changes.relation;
26890               if (!relations) return changes;
26891
26892               for (var i = 0; i < relations.length; i++) {
26893                 var relation = relations[i]; // skip relation if already sorted
26894
26895                 if (!sorted[relation['@id']]) {
26896                   processing.push(relation);
26897                 }
26898
26899                 while (processing.length > 0) {
26900                   var next = processing[0],
26901                       deps = next.member.map(resolve).filter(Boolean).filter(isNew);
26902
26903                   if (deps.length === 0) {
26904                     sorted[next['@id']] = next;
26905                     processing.shift();
26906                   } else {
26907                     processing = deps.concat(processing);
26908                   }
26909                 }
26910               }
26911
26912               changes.relation = Object.values(sorted);
26913               return changes;
26914             }
26915
26916             function rep(entity) {
26917               return entity.asJXON(changeset_id);
26918             }
26919
26920             return {
26921               osmChange: {
26922                 '@version': 0.6,
26923                 '@generator': 'iD',
26924                 'create': sort(nest(changes.created.map(rep), ['node', 'way', 'relation'])),
26925                 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
26926                 'delete': Object.assign(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), {
26927                   '@if-unused': true
26928                 })
26929               }
26930             };
26931           },
26932           asGeoJSON: function asGeoJSON() {
26933             return {};
26934           }
26935         });
26936
26937         function osmNote() {
26938           if (!(this instanceof osmNote)) {
26939             return new osmNote().initialize(arguments);
26940           } else if (arguments.length) {
26941             this.initialize(arguments);
26942           }
26943         }
26944
26945         osmNote.id = function () {
26946           return osmNote.id.next--;
26947         };
26948
26949         osmNote.id.next = -1;
26950         Object.assign(osmNote.prototype, {
26951           type: 'note',
26952           initialize: function initialize(sources) {
26953             for (var i = 0; i < sources.length; ++i) {
26954               var source = sources[i];
26955
26956               for (var prop in source) {
26957                 if (Object.prototype.hasOwnProperty.call(source, prop)) {
26958                   if (source[prop] === undefined) {
26959                     delete this[prop];
26960                   } else {
26961                     this[prop] = source[prop];
26962                   }
26963                 }
26964               }
26965             }
26966
26967             if (!this.id) {
26968               this.id = osmNote.id().toString();
26969             }
26970
26971             return this;
26972           },
26973           extent: function extent() {
26974             return new geoExtent(this.loc);
26975           },
26976           update: function update(attrs) {
26977             return osmNote(this, attrs); // {v: 1 + (this.v || 0)}
26978           },
26979           isNew: function isNew() {
26980             return this.id < 0;
26981           },
26982           move: function move(loc) {
26983             return this.update({
26984               loc: loc
26985             });
26986           }
26987         });
26988
26989         function osmRelation() {
26990           if (!(this instanceof osmRelation)) {
26991             return new osmRelation().initialize(arguments);
26992           } else if (arguments.length) {
26993             this.initialize(arguments);
26994           }
26995         }
26996         osmEntity.relation = osmRelation;
26997         osmRelation.prototype = Object.create(osmEntity.prototype);
26998
26999         osmRelation.creationOrder = function (a, b) {
27000           var aId = parseInt(osmEntity.id.toOSM(a.id), 10);
27001           var bId = parseInt(osmEntity.id.toOSM(b.id), 10);
27002           if (aId < 0 || bId < 0) return aId - bId;
27003           return bId - aId;
27004         };
27005
27006         Object.assign(osmRelation.prototype, {
27007           type: 'relation',
27008           members: [],
27009           copy: function copy(resolver, copies) {
27010             if (copies[this.id]) return copies[this.id];
27011             var copy = osmEntity.prototype.copy.call(this, resolver, copies);
27012             var members = this.members.map(function (member) {
27013               return Object.assign({}, member, {
27014                 id: resolver.entity(member.id).copy(resolver, copies).id
27015               });
27016             });
27017             copy = copy.update({
27018               members: members
27019             });
27020             copies[this.id] = copy;
27021             return copy;
27022           },
27023           extent: function extent(resolver, memo) {
27024             return resolver["transient"](this, 'extent', function () {
27025               if (memo && memo[this.id]) return geoExtent();
27026               memo = memo || {};
27027               memo[this.id] = true;
27028               var extent = geoExtent();
27029
27030               for (var i = 0; i < this.members.length; i++) {
27031                 var member = resolver.hasEntity(this.members[i].id);
27032
27033                 if (member) {
27034                   extent._extend(member.extent(resolver, memo));
27035                 }
27036               }
27037
27038               return extent;
27039             });
27040           },
27041           geometry: function geometry(graph) {
27042             return graph["transient"](this, 'geometry', function () {
27043               return this.isMultipolygon() ? 'area' : 'relation';
27044             });
27045           },
27046           isDegenerate: function isDegenerate() {
27047             return this.members.length === 0;
27048           },
27049           // Return an array of members, each extended with an 'index' property whose value
27050           // is the member index.
27051           indexedMembers: function indexedMembers() {
27052             var result = new Array(this.members.length);
27053
27054             for (var i = 0; i < this.members.length; i++) {
27055               result[i] = Object.assign({}, this.members[i], {
27056                 index: i
27057               });
27058             }
27059
27060             return result;
27061           },
27062           // Return the first member with the given role. A copy of the member object
27063           // is returned, extended with an 'index' property whose value is the member index.
27064           memberByRole: function memberByRole(role) {
27065             for (var i = 0; i < this.members.length; i++) {
27066               if (this.members[i].role === role) {
27067                 return Object.assign({}, this.members[i], {
27068                   index: i
27069                 });
27070               }
27071             }
27072           },
27073           // Same as memberByRole, but returns all members with the given role
27074           membersByRole: function membersByRole(role) {
27075             var result = [];
27076
27077             for (var i = 0; i < this.members.length; i++) {
27078               if (this.members[i].role === role) {
27079                 result.push(Object.assign({}, this.members[i], {
27080                   index: i
27081                 }));
27082               }
27083             }
27084
27085             return result;
27086           },
27087           // Return the first member with the given id. A copy of the member object
27088           // is returned, extended with an 'index' property whose value is the member index.
27089           memberById: function memberById(id) {
27090             for (var i = 0; i < this.members.length; i++) {
27091               if (this.members[i].id === id) {
27092                 return Object.assign({}, this.members[i], {
27093                   index: i
27094                 });
27095               }
27096             }
27097           },
27098           // Return the first member with the given id and role. A copy of the member object
27099           // is returned, extended with an 'index' property whose value is the member index.
27100           memberByIdAndRole: function memberByIdAndRole(id, role) {
27101             for (var i = 0; i < this.members.length; i++) {
27102               if (this.members[i].id === id && this.members[i].role === role) {
27103                 return Object.assign({}, this.members[i], {
27104                   index: i
27105                 });
27106               }
27107             }
27108           },
27109           addMember: function addMember(member, index) {
27110             var members = this.members.slice();
27111             members.splice(index === undefined ? members.length : index, 0, member);
27112             return this.update({
27113               members: members
27114             });
27115           },
27116           updateMember: function updateMember(member, index) {
27117             var members = this.members.slice();
27118             members.splice(index, 1, Object.assign({}, members[index], member));
27119             return this.update({
27120               members: members
27121             });
27122           },
27123           removeMember: function removeMember(index) {
27124             var members = this.members.slice();
27125             members.splice(index, 1);
27126             return this.update({
27127               members: members
27128             });
27129           },
27130           removeMembersWithID: function removeMembersWithID(id) {
27131             var members = this.members.filter(function (m) {
27132               return m.id !== id;
27133             });
27134             return this.update({
27135               members: members
27136             });
27137           },
27138           moveMember: function moveMember(fromIndex, toIndex) {
27139             var members = this.members.slice();
27140             members.splice(toIndex, 0, members.splice(fromIndex, 1)[0]);
27141             return this.update({
27142               members: members
27143             });
27144           },
27145           // Wherever a member appears with id `needle.id`, replace it with a member
27146           // with id `replacement.id`, type `replacement.type`, and the original role,
27147           // By default, adding a duplicate member (by id and role) is prevented.
27148           // Return an updated relation.
27149           replaceMember: function replaceMember(needle, replacement, keepDuplicates) {
27150             if (!this.memberById(needle.id)) return this;
27151             var members = [];
27152
27153             for (var i = 0; i < this.members.length; i++) {
27154               var member = this.members[i];
27155
27156               if (member.id !== needle.id) {
27157                 members.push(member);
27158               } else if (keepDuplicates || !this.memberByIdAndRole(replacement.id, member.role)) {
27159                 members.push({
27160                   id: replacement.id,
27161                   type: replacement.type,
27162                   role: member.role
27163                 });
27164               }
27165             }
27166
27167             return this.update({
27168               members: members
27169             });
27170           },
27171           asJXON: function asJXON(changeset_id) {
27172             var r = {
27173               relation: {
27174                 '@id': this.osmId(),
27175                 '@version': this.version || 0,
27176                 member: this.members.map(function (member) {
27177                   return {
27178                     keyAttributes: {
27179                       type: member.type,
27180                       role: member.role,
27181                       ref: osmEntity.id.toOSM(member.id)
27182                     }
27183                   };
27184                 }, this),
27185                 tag: Object.keys(this.tags).map(function (k) {
27186                   return {
27187                     keyAttributes: {
27188                       k: k,
27189                       v: this.tags[k]
27190                     }
27191                   };
27192                 }, this)
27193               }
27194             };
27195
27196             if (changeset_id) {
27197               r.relation['@changeset'] = changeset_id;
27198             }
27199
27200             return r;
27201           },
27202           asGeoJSON: function asGeoJSON(resolver) {
27203             return resolver["transient"](this, 'GeoJSON', function () {
27204               if (this.isMultipolygon()) {
27205                 return {
27206                   type: 'MultiPolygon',
27207                   coordinates: this.multipolygon(resolver)
27208                 };
27209               } else {
27210                 return {
27211                   type: 'FeatureCollection',
27212                   properties: this.tags,
27213                   features: this.members.map(function (member) {
27214                     return Object.assign({
27215                       role: member.role
27216                     }, resolver.entity(member.id).asGeoJSON(resolver));
27217                   })
27218                 };
27219               }
27220             });
27221           },
27222           area: function area(resolver) {
27223             return resolver["transient"](this, 'area', function () {
27224               return d3_geoArea(this.asGeoJSON(resolver));
27225             });
27226           },
27227           isMultipolygon: function isMultipolygon() {
27228             return this.tags.type === 'multipolygon';
27229           },
27230           isComplete: function isComplete(resolver) {
27231             for (var i = 0; i < this.members.length; i++) {
27232               if (!resolver.hasEntity(this.members[i].id)) {
27233                 return false;
27234               }
27235             }
27236
27237             return true;
27238           },
27239           hasFromViaTo: function hasFromViaTo() {
27240             return this.members.some(function (m) {
27241               return m.role === 'from';
27242             }) && this.members.some(function (m) {
27243               return m.role === 'via';
27244             }) && this.members.some(function (m) {
27245               return m.role === 'to';
27246             });
27247           },
27248           isRestriction: function isRestriction() {
27249             return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
27250           },
27251           isValidRestriction: function isValidRestriction() {
27252             if (!this.isRestriction()) return false;
27253             var froms = this.members.filter(function (m) {
27254               return m.role === 'from';
27255             });
27256             var vias = this.members.filter(function (m) {
27257               return m.role === 'via';
27258             });
27259             var tos = this.members.filter(function (m) {
27260               return m.role === 'to';
27261             });
27262             if (froms.length !== 1 && this.tags.restriction !== 'no_entry') return false;
27263             if (froms.some(function (m) {
27264               return m.type !== 'way';
27265             })) return false;
27266             if (tos.length !== 1 && this.tags.restriction !== 'no_exit') return false;
27267             if (tos.some(function (m) {
27268               return m.type !== 'way';
27269             })) return false;
27270             if (vias.length === 0) return false;
27271             if (vias.length > 1 && vias.some(function (m) {
27272               return m.type !== 'way';
27273             })) return false;
27274             return true;
27275           },
27276           // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
27277           // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
27278           //
27279           // This corresponds to the structure needed for rendering a multipolygon path using a
27280           // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
27281           //
27282           // In the case of invalid geometries, this function will still return a result which
27283           // includes the nodes of all way members, but some Nds may be unclosed and some inner
27284           // rings not matched with the intended outer ring.
27285           //
27286           multipolygon: function multipolygon(resolver) {
27287             var outers = this.members.filter(function (m) {
27288               return 'outer' === (m.role || 'outer');
27289             });
27290             var inners = this.members.filter(function (m) {
27291               return 'inner' === m.role;
27292             });
27293             outers = osmJoinWays(outers, resolver);
27294             inners = osmJoinWays(inners, resolver);
27295
27296             var sequenceToLineString = function sequenceToLineString(sequence) {
27297               if (sequence.nodes.length > 2 && sequence.nodes[0] !== sequence.nodes[sequence.nodes.length - 1]) {
27298                 // close unclosed parts to ensure correct area rendering - #2945
27299                 sequence.nodes.push(sequence.nodes[0]);
27300               }
27301
27302               return sequence.nodes.map(function (node) {
27303                 return node.loc;
27304               });
27305             };
27306
27307             outers = outers.map(sequenceToLineString);
27308             inners = inners.map(sequenceToLineString);
27309             var result = outers.map(function (o) {
27310               // Heuristic for detecting counterclockwise winding order. Assumes
27311               // that OpenStreetMap polygons are not hemisphere-spanning.
27312               return [d3_geoArea({
27313                 type: 'Polygon',
27314                 coordinates: [o]
27315               }) > 2 * Math.PI ? o.reverse() : o];
27316             });
27317
27318             function findOuter(inner) {
27319               var o, outer;
27320
27321               for (o = 0; o < outers.length; o++) {
27322                 outer = outers[o];
27323                 if (geoPolygonContainsPolygon(outer, inner)) return o;
27324               }
27325
27326               for (o = 0; o < outers.length; o++) {
27327                 outer = outers[o];
27328                 if (geoPolygonIntersectsPolygon(outer, inner, false)) return o;
27329               }
27330             }
27331
27332             for (var i = 0; i < inners.length; i++) {
27333               var inner = inners[i];
27334
27335               if (d3_geoArea({
27336                 type: 'Polygon',
27337                 coordinates: [inner]
27338               }) < 2 * Math.PI) {
27339                 inner = inner.reverse();
27340               }
27341
27342               var o = findOuter(inners[i]);
27343
27344               if (o !== undefined) {
27345                 result[o].push(inners[i]);
27346               } else {
27347                 result.push([inners[i]]); // Invalid geometry
27348               }
27349             }
27350
27351             return result;
27352           }
27353         });
27354
27355         var QAItem = /*#__PURE__*/function () {
27356           function QAItem(loc, service, itemType, id, props) {
27357             _classCallCheck(this, QAItem);
27358
27359             // Store required properties
27360             this.loc = loc;
27361             this.service = service.title;
27362             this.itemType = itemType; // All issues must have an ID for selection, use generic if none specified
27363
27364             this.id = id ? id : "".concat(QAItem.id());
27365             this.update(props); // Some QA services have marker icons to differentiate issues
27366
27367             if (service && typeof service.getIcon === 'function') {
27368               this.icon = service.getIcon(itemType);
27369             }
27370           }
27371
27372           _createClass(QAItem, [{
27373             key: "update",
27374             value: function update(props) {
27375               var _this = this;
27376
27377               // You can't override this initial information
27378               var loc = this.loc,
27379                   service = this.service,
27380                   itemType = this.itemType,
27381                   id = this.id;
27382               Object.keys(props).forEach(function (prop) {
27383                 return _this[prop] = props[prop];
27384               });
27385               this.loc = loc;
27386               this.service = service;
27387               this.itemType = itemType;
27388               this.id = id;
27389               return this;
27390             } // Generic handling for newly created QAItems
27391
27392           }], [{
27393             key: "id",
27394             value: function id() {
27395               return this.nextId--;
27396             }
27397           }]);
27398
27399           return QAItem;
27400         }();
27401         QAItem.nextId = -1;
27402
27403         //
27404         // Optionally, split only the given ways, if multiple ways share
27405         // the given node.
27406         //
27407         // This is the inverse of `iD.actionJoin`.
27408         //
27409         // For testing convenience, accepts an ID to assign to the new way.
27410         // Normally, this will be undefined and the way will automatically
27411         // be assigned a new ID.
27412         //
27413         // Reference:
27414         //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
27415         //
27416
27417         function actionSplit(nodeIds, newWayIds) {
27418           // accept single ID for backwards-compatiblity
27419           if (typeof nodeIds === 'string') nodeIds = [nodeIds];
27420
27421           var _wayIDs; // the strategy for picking which way will have a new version and which way is newly created
27422
27423
27424           var _keepHistoryOn = 'longest'; // 'longest', 'first'
27425           // The IDs of the ways actually created by running this action
27426
27427           var _createdWayIDs = [];
27428
27429           function dist(graph, nA, nB) {
27430             var locA = graph.entity(nA).loc;
27431             var locB = graph.entity(nB).loc;
27432             var epsilon = 1e-6;
27433             return locA && locB ? geoSphericalDistance(locA, locB) : epsilon;
27434           } // If the way is closed, we need to search for a partner node
27435           // to split the way at.
27436           //
27437           // The following looks for a node that is both far away from
27438           // the initial node in terms of way segment length and nearby
27439           // in terms of beeline-distance. This assures that areas get
27440           // split on the most "natural" points (independent of the number
27441           // of nodes).
27442           // For example: bone-shaped areas get split across their waist
27443           // line, circles across the diameter.
27444
27445
27446           function splitArea(nodes, idxA, graph) {
27447             var lengths = new Array(nodes.length);
27448             var length;
27449             var i;
27450             var best = 0;
27451             var idxB;
27452
27453             function wrap(index) {
27454               return utilWrap(index, nodes.length);
27455             } // calculate lengths
27456
27457
27458             length = 0;
27459
27460             for (i = wrap(idxA + 1); i !== idxA; i = wrap(i + 1)) {
27461               length += dist(graph, nodes[i], nodes[wrap(i - 1)]);
27462               lengths[i] = length;
27463             }
27464
27465             length = 0;
27466
27467             for (i = wrap(idxA - 1); i !== idxA; i = wrap(i - 1)) {
27468               length += dist(graph, nodes[i], nodes[wrap(i + 1)]);
27469
27470               if (length < lengths[i]) {
27471                 lengths[i] = length;
27472               }
27473             } // determine best opposite node to split
27474
27475
27476             for (i = 0; i < nodes.length; i++) {
27477               var cost = lengths[i] / dist(graph, nodes[idxA], nodes[i]);
27478
27479               if (cost > best) {
27480                 idxB = i;
27481                 best = cost;
27482               }
27483             }
27484
27485             return idxB;
27486           }
27487
27488           function totalLengthBetweenNodes(graph, nodes) {
27489             var totalLength = 0;
27490
27491             for (var i = 0; i < nodes.length - 1; i++) {
27492               totalLength += dist(graph, nodes[i], nodes[i + 1]);
27493             }
27494
27495             return totalLength;
27496           }
27497
27498           function split(graph, nodeId, wayA, newWayId) {
27499             var wayB = osmWay({
27500               id: newWayId,
27501               tags: wayA.tags
27502             }); // `wayB` is the NEW way
27503
27504             var origNodes = wayA.nodes.slice();
27505             var nodesA;
27506             var nodesB;
27507             var isArea = wayA.isArea();
27508             var isOuter = osmIsOldMultipolygonOuterMember(wayA, graph);
27509
27510             if (wayA.isClosed()) {
27511               var nodes = wayA.nodes.slice(0, -1);
27512               var idxA = nodes.indexOf(nodeId);
27513               var idxB = splitArea(nodes, idxA, graph);
27514
27515               if (idxB < idxA) {
27516                 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
27517                 nodesB = nodes.slice(idxB, idxA + 1);
27518               } else {
27519                 nodesA = nodes.slice(idxA, idxB + 1);
27520                 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
27521               }
27522             } else {
27523               var idx = wayA.nodes.indexOf(nodeId, 1);
27524               nodesA = wayA.nodes.slice(0, idx + 1);
27525               nodesB = wayA.nodes.slice(idx);
27526             }
27527
27528             var lengthA = totalLengthBetweenNodes(graph, nodesA);
27529             var lengthB = totalLengthBetweenNodes(graph, nodesB);
27530
27531             if (_keepHistoryOn === 'longest' && lengthB > lengthA) {
27532               // keep the history on the longer way, regardless of the node count
27533               wayA = wayA.update({
27534                 nodes: nodesB
27535               });
27536               wayB = wayB.update({
27537                 nodes: nodesA
27538               });
27539               var temp = lengthA;
27540               lengthA = lengthB;
27541               lengthB = temp;
27542             } else {
27543               wayA = wayA.update({
27544                 nodes: nodesA
27545               });
27546               wayB = wayB.update({
27547                 nodes: nodesB
27548               });
27549             }
27550
27551             if (wayA.tags.step_count) {
27552               // divide up the the step count proportionally between the two ways
27553               var stepCount = parseFloat(wayA.tags.step_count);
27554
27555               if (stepCount && // ensure a number
27556               isFinite(stepCount) && // ensure positive
27557               stepCount > 0 && // ensure integer
27558               Math.round(stepCount) === stepCount) {
27559                 var tagsA = Object.assign({}, wayA.tags);
27560                 var tagsB = Object.assign({}, wayB.tags);
27561                 var ratioA = lengthA / (lengthA + lengthB);
27562                 var countA = Math.round(stepCount * ratioA);
27563                 tagsA.step_count = countA.toString();
27564                 tagsB.step_count = (stepCount - countA).toString();
27565                 wayA = wayA.update({
27566                   tags: tagsA
27567                 });
27568                 wayB = wayB.update({
27569                   tags: tagsB
27570                 });
27571               }
27572             }
27573
27574             graph = graph.replace(wayA);
27575             graph = graph.replace(wayB);
27576             graph.parentRelations(wayA).forEach(function (relation) {
27577               var member; // Turn restrictions - make sure:
27578               // 1. Splitting a FROM/TO way - only `wayA` OR `wayB` remains in relation
27579               //    (whichever one is connected to the VIA node/ways)
27580               // 2. Splitting a VIA way - `wayB` remains in relation as a VIA way
27581
27582               if (relation.hasFromViaTo()) {
27583                 var f = relation.memberByRole('from');
27584                 var v = relation.membersByRole('via');
27585                 var t = relation.memberByRole('to');
27586                 var i; // 1. split a FROM/TO
27587
27588                 if (f.id === wayA.id || t.id === wayA.id) {
27589                   var keepB = false;
27590
27591                   if (v.length === 1 && v[0].type === 'node') {
27592                     // check via node
27593                     keepB = wayB.contains(v[0].id);
27594                   } else {
27595                     // check via way(s)
27596                     for (i = 0; i < v.length; i++) {
27597                       if (v[i].type === 'way') {
27598                         var wayVia = graph.hasEntity(v[i].id);
27599
27600                         if (wayVia && utilArrayIntersection(wayB.nodes, wayVia.nodes).length) {
27601                           keepB = true;
27602                           break;
27603                         }
27604                       }
27605                     }
27606                   }
27607
27608                   if (keepB) {
27609                     relation = relation.replaceMember(wayA, wayB);
27610                     graph = graph.replace(relation);
27611                   } // 2. split a VIA
27612
27613                 } else {
27614                   for (i = 0; i < v.length; i++) {
27615                     if (v[i].type === 'way' && v[i].id === wayA.id) {
27616                       member = {
27617                         id: wayB.id,
27618                         type: 'way',
27619                         role: 'via'
27620                       };
27621                       graph = actionAddMember(relation.id, member, v[i].index + 1)(graph);
27622                       break;
27623                     }
27624                   }
27625                 } // All other relations (Routes, Multipolygons, etc):
27626                 // 1. Both `wayA` and `wayB` remain in the relation
27627                 // 2. But must be inserted as a pair (see `actionAddMember` for details)
27628
27629               } else {
27630                 if (relation === isOuter) {
27631                   graph = graph.replace(relation.mergeTags(wayA.tags));
27632                   graph = graph.replace(wayA.update({
27633                     tags: {}
27634                   }));
27635                   graph = graph.replace(wayB.update({
27636                     tags: {}
27637                   }));
27638                 }
27639
27640                 member = {
27641                   id: wayB.id,
27642                   type: 'way',
27643                   role: relation.memberById(wayA.id).role
27644                 };
27645                 var insertPair = {
27646                   originalID: wayA.id,
27647                   insertedID: wayB.id,
27648                   nodes: origNodes
27649                 };
27650                 graph = actionAddMember(relation.id, member, undefined, insertPair)(graph);
27651               }
27652             });
27653
27654             if (!isOuter && isArea) {
27655               var multipolygon = osmRelation({
27656                 tags: Object.assign({}, wayA.tags, {
27657                   type: 'multipolygon'
27658                 }),
27659                 members: [{
27660                   id: wayA.id,
27661                   role: 'outer',
27662                   type: 'way'
27663                 }, {
27664                   id: wayB.id,
27665                   role: 'outer',
27666                   type: 'way'
27667                 }]
27668               });
27669               graph = graph.replace(multipolygon);
27670               graph = graph.replace(wayA.update({
27671                 tags: {}
27672               }));
27673               graph = graph.replace(wayB.update({
27674                 tags: {}
27675               }));
27676             }
27677
27678             _createdWayIDs.push(wayB.id);
27679
27680             return graph;
27681           }
27682
27683           var action = function action(graph) {
27684             _createdWayIDs = [];
27685             var newWayIndex = 0;
27686
27687             for (var i = 0; i < nodeIds.length; i++) {
27688               var nodeId = nodeIds[i];
27689               var candidates = action.waysForNode(nodeId, graph);
27690
27691               for (var j = 0; j < candidates.length; j++) {
27692                 graph = split(graph, nodeId, candidates[j], newWayIds && newWayIds[newWayIndex]);
27693                 newWayIndex += 1;
27694               }
27695             }
27696
27697             return graph;
27698           };
27699
27700           action.getCreatedWayIDs = function () {
27701             return _createdWayIDs;
27702           };
27703
27704           action.waysForNode = function (nodeId, graph) {
27705             var node = graph.entity(nodeId);
27706             var splittableParents = graph.parentWays(node).filter(isSplittable);
27707
27708             if (!_wayIDs) {
27709               // If the ways to split aren't specified, only split the lines.
27710               // If there are no lines to split, split the areas.
27711               var hasLine = splittableParents.some(function (parent) {
27712                 return parent.geometry(graph) === 'line';
27713               });
27714
27715               if (hasLine) {
27716                 return splittableParents.filter(function (parent) {
27717                   return parent.geometry(graph) === 'line';
27718                 });
27719               }
27720             }
27721
27722             return splittableParents;
27723
27724             function isSplittable(parent) {
27725               // If the ways to split are specified, ignore everything else.
27726               if (_wayIDs && _wayIDs.indexOf(parent.id) === -1) return false; // We can fake splitting closed ways at their endpoints...
27727
27728               if (parent.isClosed()) return true; // otherwise, we can't split nodes at their endpoints.
27729
27730               for (var i = 1; i < parent.nodes.length - 1; i++) {
27731                 if (parent.nodes[i] === nodeId) return true;
27732               }
27733
27734               return false;
27735             }
27736           };
27737
27738           action.ways = function (graph) {
27739             return utilArrayUniq([].concat.apply([], nodeIds.map(function (nodeId) {
27740               return action.waysForNode(nodeId, graph);
27741             })));
27742           };
27743
27744           action.disabled = function (graph) {
27745             for (var i = 0; i < nodeIds.length; i++) {
27746               var nodeId = nodeIds[i];
27747               var candidates = action.waysForNode(nodeId, graph);
27748
27749               if (candidates.length === 0 || _wayIDs && _wayIDs.length !== candidates.length) {
27750                 return 'not_eligible';
27751               }
27752             }
27753           };
27754
27755           action.limitWays = function (val) {
27756             if (!arguments.length) return _wayIDs;
27757             _wayIDs = val;
27758             return action;
27759           };
27760
27761           action.keepHistoryOn = function (val) {
27762             if (!arguments.length) return _keepHistoryOn;
27763             _keepHistoryOn = val;
27764             return action;
27765           };
27766
27767           return action;
27768         }
27769
27770         function coreGraph(other, mutable) {
27771           if (!(this instanceof coreGraph)) return new coreGraph(other, mutable);
27772
27773           if (other instanceof coreGraph) {
27774             var base = other.base();
27775             this.entities = Object.assign(Object.create(base.entities), other.entities);
27776             this._parentWays = Object.assign(Object.create(base.parentWays), other._parentWays);
27777             this._parentRels = Object.assign(Object.create(base.parentRels), other._parentRels);
27778           } else {
27779             this.entities = Object.create({});
27780             this._parentWays = Object.create({});
27781             this._parentRels = Object.create({});
27782             this.rebase(other || [], [this]);
27783           }
27784
27785           this.transients = {};
27786           this._childNodes = {};
27787           this.frozen = !mutable;
27788         }
27789         coreGraph.prototype = {
27790           hasEntity: function hasEntity(id) {
27791             return this.entities[id];
27792           },
27793           entity: function entity(id) {
27794             var entity = this.entities[id]; //https://github.com/openstreetmap/iD/issues/3973#issuecomment-307052376
27795
27796             if (!entity) {
27797               entity = this.entities.__proto__[id]; // eslint-disable-line no-proto
27798             }
27799
27800             if (!entity) {
27801               throw new Error('entity ' + id + ' not found');
27802             }
27803
27804             return entity;
27805           },
27806           geometry: function geometry(id) {
27807             return this.entity(id).geometry(this);
27808           },
27809           "transient": function transient(entity, key, fn) {
27810             var id = entity.id;
27811             var transients = this.transients[id] || (this.transients[id] = {});
27812
27813             if (transients[key] !== undefined) {
27814               return transients[key];
27815             }
27816
27817             transients[key] = fn.call(entity);
27818             return transients[key];
27819           },
27820           parentWays: function parentWays(entity) {
27821             var parents = this._parentWays[entity.id];
27822             var result = [];
27823
27824             if (parents) {
27825               parents.forEach(function (id) {
27826                 result.push(this.entity(id));
27827               }, this);
27828             }
27829
27830             return result;
27831           },
27832           isPoi: function isPoi(entity) {
27833             var parents = this._parentWays[entity.id];
27834             return !parents || parents.size === 0;
27835           },
27836           isShared: function isShared(entity) {
27837             var parents = this._parentWays[entity.id];
27838             return parents && parents.size > 1;
27839           },
27840           parentRelations: function parentRelations(entity) {
27841             var parents = this._parentRels[entity.id];
27842             var result = [];
27843
27844             if (parents) {
27845               parents.forEach(function (id) {
27846                 result.push(this.entity(id));
27847               }, this);
27848             }
27849
27850             return result;
27851           },
27852           parentMultipolygons: function parentMultipolygons(entity) {
27853             return this.parentRelations(entity).filter(function (relation) {
27854               return relation.isMultipolygon();
27855             });
27856           },
27857           childNodes: function childNodes(entity) {
27858             if (this._childNodes[entity.id]) return this._childNodes[entity.id];
27859             if (!entity.nodes) return [];
27860             var nodes = [];
27861
27862             for (var i = 0; i < entity.nodes.length; i++) {
27863               nodes[i] = this.entity(entity.nodes[i]);
27864             }
27865             this._childNodes[entity.id] = nodes;
27866             return this._childNodes[entity.id];
27867           },
27868           base: function base() {
27869             return {
27870               'entities': Object.getPrototypeOf(this.entities),
27871               'parentWays': Object.getPrototypeOf(this._parentWays),
27872               'parentRels': Object.getPrototypeOf(this._parentRels)
27873             };
27874           },
27875           // Unlike other graph methods, rebase mutates in place. This is because it
27876           // is used only during the history operation that merges newly downloaded
27877           // data into each state. To external consumers, it should appear as if the
27878           // graph always contained the newly downloaded data.
27879           rebase: function rebase(entities, stack, force) {
27880             var base = this.base();
27881             var i, j, k, id;
27882
27883             for (i = 0; i < entities.length; i++) {
27884               var entity = entities[i];
27885               if (!entity.visible || !force && base.entities[entity.id]) continue; // Merging data into the base graph
27886
27887               base.entities[entity.id] = entity;
27888
27889               this._updateCalculated(undefined, entity, base.parentWays, base.parentRels); // Restore provisionally-deleted nodes that are discovered to have an extant parent
27890
27891
27892               if (entity.type === 'way') {
27893                 for (j = 0; j < entity.nodes.length; j++) {
27894                   id = entity.nodes[j];
27895
27896                   for (k = 1; k < stack.length; k++) {
27897                     var ents = stack[k].entities;
27898
27899                     if (ents.hasOwnProperty(id) && ents[id] === undefined) {
27900                       delete ents[id];
27901                     }
27902                   }
27903                 }
27904               }
27905             }
27906
27907             for (i = 0; i < stack.length; i++) {
27908               stack[i]._updateRebased();
27909             }
27910           },
27911           _updateRebased: function _updateRebased() {
27912             var base = this.base();
27913             Object.keys(this._parentWays).forEach(function (child) {
27914               if (base.parentWays[child]) {
27915                 base.parentWays[child].forEach(function (id) {
27916                   if (!this.entities.hasOwnProperty(id)) {
27917                     this._parentWays[child].add(id);
27918                   }
27919                 }, this);
27920               }
27921             }, this);
27922             Object.keys(this._parentRels).forEach(function (child) {
27923               if (base.parentRels[child]) {
27924                 base.parentRels[child].forEach(function (id) {
27925                   if (!this.entities.hasOwnProperty(id)) {
27926                     this._parentRels[child].add(id);
27927                   }
27928                 }, this);
27929               }
27930             }, this);
27931             this.transients = {}; // this._childNodes is not updated, under the assumption that
27932             // ways are always downloaded with their child nodes.
27933           },
27934           // Updates calculated properties (parentWays, parentRels) for the specified change
27935           _updateCalculated: function _updateCalculated(oldentity, entity, parentWays, parentRels) {
27936             parentWays = parentWays || this._parentWays;
27937             parentRels = parentRels || this._parentRels;
27938             var type = entity && entity.type || oldentity && oldentity.type;
27939             var removed, added, i;
27940
27941             if (type === 'way') {
27942               // Update parentWays
27943               if (oldentity && entity) {
27944                 removed = utilArrayDifference(oldentity.nodes, entity.nodes);
27945                 added = utilArrayDifference(entity.nodes, oldentity.nodes);
27946               } else if (oldentity) {
27947                 removed = oldentity.nodes;
27948                 added = [];
27949               } else if (entity) {
27950                 removed = [];
27951                 added = entity.nodes;
27952               }
27953
27954               for (i = 0; i < removed.length; i++) {
27955                 // make a copy of prototype property, store as own property, and update..
27956                 parentWays[removed[i]] = new Set(parentWays[removed[i]]);
27957                 parentWays[removed[i]]["delete"](oldentity.id);
27958               }
27959
27960               for (i = 0; i < added.length; i++) {
27961                 // make a copy of prototype property, store as own property, and update..
27962                 parentWays[added[i]] = new Set(parentWays[added[i]]);
27963                 parentWays[added[i]].add(entity.id);
27964               }
27965             } else if (type === 'relation') {
27966               // Update parentRels
27967               // diff only on the IDs since the same entity can be a member multiple times with different roles
27968               var oldentityMemberIDs = oldentity ? oldentity.members.map(function (m) {
27969                 return m.id;
27970               }) : [];
27971               var entityMemberIDs = entity ? entity.members.map(function (m) {
27972                 return m.id;
27973               }) : [];
27974
27975               if (oldentity && entity) {
27976                 removed = utilArrayDifference(oldentityMemberIDs, entityMemberIDs);
27977                 added = utilArrayDifference(entityMemberIDs, oldentityMemberIDs);
27978               } else if (oldentity) {
27979                 removed = oldentityMemberIDs;
27980                 added = [];
27981               } else if (entity) {
27982                 removed = [];
27983                 added = entityMemberIDs;
27984               }
27985
27986               for (i = 0; i < removed.length; i++) {
27987                 // make a copy of prototype property, store as own property, and update..
27988                 parentRels[removed[i]] = new Set(parentRels[removed[i]]);
27989                 parentRels[removed[i]]["delete"](oldentity.id);
27990               }
27991
27992               for (i = 0; i < added.length; i++) {
27993                 // make a copy of prototype property, store as own property, and update..
27994                 parentRels[added[i]] = new Set(parentRels[added[i]]);
27995                 parentRels[added[i]].add(entity.id);
27996               }
27997             }
27998           },
27999           replace: function replace(entity) {
28000             if (this.entities[entity.id] === entity) return this;
28001             return this.update(function () {
28002               this._updateCalculated(this.entities[entity.id], entity);
28003
28004               this.entities[entity.id] = entity;
28005             });
28006           },
28007           remove: function remove(entity) {
28008             return this.update(function () {
28009               this._updateCalculated(entity, undefined);
28010
28011               this.entities[entity.id] = undefined;
28012             });
28013           },
28014           revert: function revert(id) {
28015             var baseEntity = this.base().entities[id];
28016             var headEntity = this.entities[id];
28017             if (headEntity === baseEntity) return this;
28018             return this.update(function () {
28019               this._updateCalculated(headEntity, baseEntity);
28020
28021               delete this.entities[id];
28022             });
28023           },
28024           update: function update() {
28025             var graph = this.frozen ? coreGraph(this, true) : this;
28026
28027             for (var i = 0; i < arguments.length; i++) {
28028               arguments[i].call(graph, graph);
28029             }
28030
28031             if (this.frozen) graph.frozen = true;
28032             return graph;
28033           },
28034           // Obliterates any existing entities
28035           load: function load(entities) {
28036             var base = this.base();
28037             this.entities = Object.create(base.entities);
28038
28039             for (var i in entities) {
28040               this.entities[i] = entities[i];
28041
28042               this._updateCalculated(base.entities[i], this.entities[i]);
28043             }
28044
28045             return this;
28046           }
28047         };
28048
28049         function osmTurn(turn) {
28050           if (!(this instanceof osmTurn)) {
28051             return new osmTurn(turn);
28052           }
28053
28054           Object.assign(this, turn);
28055         }
28056         function osmIntersection(graph, startVertexId, maxDistance) {
28057           maxDistance = maxDistance || 30; // in meters
28058
28059           var vgraph = coreGraph(); // virtual graph
28060
28061           var i, j, k;
28062
28063           function memberOfRestriction(entity) {
28064             return graph.parentRelations(entity).some(function (r) {
28065               return r.isRestriction();
28066             });
28067           }
28068
28069           function isRoad(way) {
28070             if (way.isArea() || way.isDegenerate()) return false;
28071             var roads = {
28072               'motorway': true,
28073               'motorway_link': true,
28074               'trunk': true,
28075               'trunk_link': true,
28076               'primary': true,
28077               'primary_link': true,
28078               'secondary': true,
28079               'secondary_link': true,
28080               'tertiary': true,
28081               'tertiary_link': true,
28082               'residential': true,
28083               'unclassified': true,
28084               'living_street': true,
28085               'service': true,
28086               'road': true,
28087               'track': true
28088             };
28089             return roads[way.tags.highway];
28090           }
28091
28092           var startNode = graph.entity(startVertexId);
28093           var checkVertices = [startNode];
28094           var checkWays;
28095           var vertices = [];
28096           var vertexIds = [];
28097           var vertex;
28098           var ways = [];
28099           var wayIds = [];
28100           var way;
28101           var nodes = [];
28102           var node;
28103           var parents = [];
28104           var parent; // `actions` will store whatever actions must be performed to satisfy
28105           // preconditions for adding a turn restriction to this intersection.
28106           //  - Remove any existing degenerate turn restrictions (missing from/to, etc)
28107           //  - Reverse oneways so that they are drawn in the forward direction
28108           //  - Split ways on key vertices
28109
28110           var actions = []; // STEP 1:  walk the graph outwards from starting vertex to search
28111           //  for more key vertices and ways to include in the intersection..
28112
28113           while (checkVertices.length) {
28114             vertex = checkVertices.pop(); // check this vertex for parent ways that are roads
28115
28116             checkWays = graph.parentWays(vertex);
28117             var hasWays = false;
28118
28119             for (i = 0; i < checkWays.length; i++) {
28120               way = checkWays[i];
28121               if (!isRoad(way) && !memberOfRestriction(way)) continue;
28122               ways.push(way); // it's a road, or it's already in a turn restriction
28123
28124               hasWays = true; // check the way's children for more key vertices
28125
28126               nodes = utilArrayUniq(graph.childNodes(way));
28127
28128               for (j = 0; j < nodes.length; j++) {
28129                 node = nodes[j];
28130                 if (node === vertex) continue; // same thing
28131
28132                 if (vertices.indexOf(node) !== -1) continue; // seen it already
28133
28134                 if (geoSphericalDistance(node.loc, startNode.loc) > maxDistance) continue; // too far from start
28135                 // a key vertex will have parents that are also roads
28136
28137                 var hasParents = false;
28138                 parents = graph.parentWays(node);
28139
28140                 for (k = 0; k < parents.length; k++) {
28141                   parent = parents[k];
28142                   if (parent === way) continue; // same thing
28143
28144                   if (ways.indexOf(parent) !== -1) continue; // seen it already
28145
28146                   if (!isRoad(parent)) continue; // not a road
28147
28148                   hasParents = true;
28149                   break;
28150                 }
28151
28152                 if (hasParents) {
28153                   checkVertices.push(node);
28154                 }
28155               }
28156             }
28157
28158             if (hasWays) {
28159               vertices.push(vertex);
28160             }
28161           }
28162
28163           vertices = utilArrayUniq(vertices);
28164           ways = utilArrayUniq(ways); // STEP 2:  Build a virtual graph containing only the entities in the intersection..
28165           // Everything done after this step should act on the virtual graph
28166           // Any actions that must be performed later to the main graph go in `actions` array
28167
28168           ways.forEach(function (way) {
28169             graph.childNodes(way).forEach(function (node) {
28170               vgraph = vgraph.replace(node);
28171             });
28172             vgraph = vgraph.replace(way);
28173             graph.parentRelations(way).forEach(function (relation) {
28174               if (relation.isRestriction()) {
28175                 if (relation.isValidRestriction(graph)) {
28176                   vgraph = vgraph.replace(relation);
28177                 } else if (relation.isComplete(graph)) {
28178                   actions.push(actionDeleteRelation(relation.id));
28179                 }
28180               }
28181             });
28182           }); // STEP 3:  Force all oneways to be drawn in the forward direction
28183
28184           ways.forEach(function (w) {
28185             var way = vgraph.entity(w.id);
28186
28187             if (way.tags.oneway === '-1') {
28188               var action = actionReverse(way.id, {
28189                 reverseOneway: true
28190               });
28191               actions.push(action);
28192               vgraph = action(vgraph);
28193             }
28194           }); // STEP 4:  Split ways on key vertices
28195
28196           var origCount = osmEntity.id.next.way;
28197           vertices.forEach(function (v) {
28198             // This is an odd way to do it, but we need to find all the ways that
28199             // will be split here, then split them one at a time to ensure that these
28200             // actions can be replayed on the main graph exactly in the same order.
28201             // (It is unintuitive, but the order of ways returned from graph.parentWays()
28202             // is arbitrary, depending on how the main graph and vgraph were built)
28203             var splitAll = actionSplit([v.id]).keepHistoryOn('first');
28204
28205             if (!splitAll.disabled(vgraph)) {
28206               splitAll.ways(vgraph).forEach(function (way) {
28207                 var splitOne = actionSplit([v.id]).limitWays([way.id]).keepHistoryOn('first');
28208                 actions.push(splitOne);
28209                 vgraph = splitOne(vgraph);
28210               });
28211             }
28212           }); // In here is where we should also split the intersection at nearby junction.
28213           //   for https://github.com/mapbox/iD-internal/issues/31
28214           // nearbyVertices.forEach(function(v) {
28215           // });
28216           // Reasons why we reset the way id count here:
28217           //  1. Continuity with way ids created by the splits so that we can replay
28218           //     these actions later if the user decides to create a turn restriction
28219           //  2. Avoids churning way ids just by hovering over a vertex
28220           //     and displaying the turn restriction editor
28221
28222           osmEntity.id.next.way = origCount; // STEP 5:  Update arrays to point to vgraph entities
28223
28224           vertexIds = vertices.map(function (v) {
28225             return v.id;
28226           });
28227           vertices = [];
28228           ways = [];
28229           vertexIds.forEach(function (id) {
28230             var vertex = vgraph.entity(id);
28231             var parents = vgraph.parentWays(vertex);
28232             vertices.push(vertex);
28233             ways = ways.concat(parents);
28234           });
28235           vertices = utilArrayUniq(vertices);
28236           ways = utilArrayUniq(ways);
28237           vertexIds = vertices.map(function (v) {
28238             return v.id;
28239           });
28240           wayIds = ways.map(function (w) {
28241             return w.id;
28242           }); // STEP 6:  Update the ways with some metadata that will be useful for
28243           // walking the intersection graph later and rendering turn arrows.
28244
28245           function withMetadata(way, vertexIds) {
28246             var __oneWay = way.isOneWay(); // which affixes are key vertices?
28247
28248
28249             var __first = vertexIds.indexOf(way.first()) !== -1;
28250
28251             var __last = vertexIds.indexOf(way.last()) !== -1; // what roles is this way eligible for?
28252
28253
28254             var __via = __first && __last;
28255
28256             var __from = __first && !__oneWay || __last;
28257
28258             var __to = __first || __last && !__oneWay;
28259
28260             return way.update({
28261               __first: __first,
28262               __last: __last,
28263               __from: __from,
28264               __via: __via,
28265               __to: __to,
28266               __oneWay: __oneWay
28267             });
28268           }
28269
28270           ways = [];
28271           wayIds.forEach(function (id) {
28272             var way = withMetadata(vgraph.entity(id), vertexIds);
28273             vgraph = vgraph.replace(way);
28274             ways.push(way);
28275           }); // STEP 7:  Simplify - This is an iterative process where we:
28276           //  1. Find trivial vertices with only 2 parents
28277           //  2. trim off the leaf way from those vertices and remove from vgraph
28278
28279           var keepGoing;
28280           var removeWayIds = [];
28281           var removeVertexIds = [];
28282
28283           do {
28284             keepGoing = false;
28285             checkVertices = vertexIds.slice();
28286
28287             for (i = 0; i < checkVertices.length; i++) {
28288               var vertexId = checkVertices[i];
28289               vertex = vgraph.hasEntity(vertexId);
28290
28291               if (!vertex) {
28292                 if (vertexIds.indexOf(vertexId) !== -1) {
28293                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
28294                 }
28295
28296                 removeVertexIds.push(vertexId);
28297                 continue;
28298               }
28299
28300               parents = vgraph.parentWays(vertex);
28301
28302               if (parents.length < 3) {
28303                 if (vertexIds.indexOf(vertexId) !== -1) {
28304                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
28305                 }
28306               }
28307
28308               if (parents.length === 2) {
28309                 // vertex with 2 parents is trivial
28310                 var a = parents[0];
28311                 var b = parents[1];
28312                 var aIsLeaf = a && !a.__via;
28313                 var bIsLeaf = b && !b.__via;
28314                 var leaf, survivor;
28315
28316                 if (aIsLeaf && !bIsLeaf) {
28317                   leaf = a;
28318                   survivor = b;
28319                 } else if (!aIsLeaf && bIsLeaf) {
28320                   leaf = b;
28321                   survivor = a;
28322                 }
28323
28324                 if (leaf && survivor) {
28325                   survivor = withMetadata(survivor, vertexIds); // update survivor way
28326
28327                   vgraph = vgraph.replace(survivor).remove(leaf); // update graph
28328
28329                   removeWayIds.push(leaf.id);
28330                   keepGoing = true;
28331                 }
28332               }
28333
28334               parents = vgraph.parentWays(vertex);
28335
28336               if (parents.length < 2) {
28337                 // vertex is no longer a key vertex
28338                 if (vertexIds.indexOf(vertexId) !== -1) {
28339                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
28340                 }
28341
28342                 removeVertexIds.push(vertexId);
28343                 keepGoing = true;
28344               }
28345
28346               if (parents.length < 1) {
28347                 // vertex is no longer attached to anything
28348                 vgraph = vgraph.remove(vertex);
28349               }
28350             }
28351           } while (keepGoing);
28352
28353           vertices = vertices.filter(function (vertex) {
28354             return removeVertexIds.indexOf(vertex.id) === -1;
28355           }).map(function (vertex) {
28356             return vgraph.entity(vertex.id);
28357           });
28358           ways = ways.filter(function (way) {
28359             return removeWayIds.indexOf(way.id) === -1;
28360           }).map(function (way) {
28361             return vgraph.entity(way.id);
28362           }); // OK!  Here is our intersection..
28363
28364           var intersection = {
28365             graph: vgraph,
28366             actions: actions,
28367             vertices: vertices,
28368             ways: ways
28369           }; // Get all the valid turns through this intersection given a starting way id.
28370           // This operates on the virtual graph for everything.
28371           //
28372           // Basically, walk through all possible paths from starting way,
28373           //   honoring the existing turn restrictions as we go (watch out for loops!)
28374           //
28375           // For each path found, generate and return a `osmTurn` datastructure.
28376           //
28377
28378           intersection.turns = function (fromWayId, maxViaWay) {
28379             if (!fromWayId) return [];
28380             if (!maxViaWay) maxViaWay = 0;
28381             var vgraph = intersection.graph;
28382             var keyVertexIds = intersection.vertices.map(function (v) {
28383               return v.id;
28384             });
28385             var start = vgraph.entity(fromWayId);
28386             if (!start || !(start.__from || start.__via)) return []; // maxViaWay=0   from-*-to              (0 vias)
28387             // maxViaWay=1   from-*-via-*-to        (1 via max)
28388             // maxViaWay=2   from-*-via-*-via-*-to  (2 vias max)
28389
28390             var maxPathLength = maxViaWay * 2 + 3;
28391             var turns = [];
28392             step(start);
28393             return turns; // traverse the intersection graph and find all the valid paths
28394
28395             function step(entity, currPath, currRestrictions, matchedRestriction) {
28396               currPath = (currPath || []).slice(); // shallow copy
28397
28398               if (currPath.length >= maxPathLength) return;
28399               currPath.push(entity.id);
28400               currRestrictions = (currRestrictions || []).slice(); // shallow copy
28401
28402               var i, j;
28403
28404               if (entity.type === 'node') {
28405                 var parents = vgraph.parentWays(entity);
28406                 var nextWays = []; // which ways can we step into?
28407
28408                 for (i = 0; i < parents.length; i++) {
28409                   var way = parents[i]; // if next way is a oneway incoming to this vertex, skip
28410
28411                   if (way.__oneWay && way.nodes[0] !== entity.id) continue; // if we have seen it before (allowing for an initial u-turn), skip
28412
28413                   if (currPath.indexOf(way.id) !== -1 && currPath.length >= 3) continue; // Check all "current" restrictions (where we've already walked the `FROM`)
28414
28415                   var restrict = null;
28416
28417                   for (j = 0; j < currRestrictions.length; j++) {
28418                     var restriction = currRestrictions[j];
28419                     var f = restriction.memberByRole('from');
28420                     var v = restriction.membersByRole('via');
28421                     var t = restriction.memberByRole('to');
28422                     var isOnly = /^only_/.test(restriction.tags.restriction); // Does the current path match this turn restriction?
28423
28424                     var matchesFrom = f.id === fromWayId;
28425                     var matchesViaTo = false;
28426                     var isAlongOnlyPath = false;
28427
28428                     if (t.id === way.id) {
28429                       // match TO
28430                       if (v.length === 1 && v[0].type === 'node') {
28431                         // match VIA node
28432                         matchesViaTo = v[0].id === entity.id && (matchesFrom && currPath.length === 2 || !matchesFrom && currPath.length > 2);
28433                       } else {
28434                         // match all VIA ways
28435                         var pathVias = [];
28436
28437                         for (k = 2; k < currPath.length; k += 2) {
28438                           // k = 2 skips FROM
28439                           pathVias.push(currPath[k]); // (path goes way-node-way...)
28440                         }
28441
28442                         var restrictionVias = [];
28443
28444                         for (k = 0; k < v.length; k++) {
28445                           if (v[k].type === 'way') {
28446                             restrictionVias.push(v[k].id);
28447                           }
28448                         }
28449
28450                         var diff = utilArrayDifference(pathVias, restrictionVias);
28451                         matchesViaTo = !diff.length;
28452                       }
28453                     } else if (isOnly) {
28454                       for (k = 0; k < v.length; k++) {
28455                         // way doesn't match TO, but is one of the via ways along the path of an "only"
28456                         if (v[k].type === 'way' && v[k].id === way.id) {
28457                           isAlongOnlyPath = true;
28458                           break;
28459                         }
28460                       }
28461                     }
28462
28463                     if (matchesViaTo) {
28464                       if (isOnly) {
28465                         restrict = {
28466                           id: restriction.id,
28467                           direct: matchesFrom,
28468                           from: f.id,
28469                           only: true,
28470                           end: true
28471                         };
28472                       } else {
28473                         restrict = {
28474                           id: restriction.id,
28475                           direct: matchesFrom,
28476                           from: f.id,
28477                           no: true,
28478                           end: true
28479                         };
28480                       }
28481                     } else {
28482                       // indirect - caused by a different nearby restriction
28483                       if (isAlongOnlyPath) {
28484                         restrict = {
28485                           id: restriction.id,
28486                           direct: false,
28487                           from: f.id,
28488                           only: true,
28489                           end: false
28490                         };
28491                       } else if (isOnly) {
28492                         restrict = {
28493                           id: restriction.id,
28494                           direct: false,
28495                           from: f.id,
28496                           no: true,
28497                           end: true
28498                         };
28499                       }
28500                     } // stop looking if we find a "direct" restriction (matching FROM, VIA, TO)
28501
28502
28503                     if (restrict && restrict.direct) break;
28504                   }
28505
28506                   nextWays.push({
28507                     way: way,
28508                     restrict: restrict
28509                   });
28510                 }
28511
28512                 nextWays.forEach(function (nextWay) {
28513                   step(nextWay.way, currPath, currRestrictions, nextWay.restrict);
28514                 });
28515               } else {
28516                 // entity.type === 'way'
28517                 if (currPath.length >= 3) {
28518                   // this is a "complete" path..
28519                   var turnPath = currPath.slice(); // shallow copy
28520                   // an indirect restriction - only include the partial path (starting at FROM)
28521
28522                   if (matchedRestriction && matchedRestriction.direct === false) {
28523                     for (i = 0; i < turnPath.length; i++) {
28524                       if (turnPath[i] === matchedRestriction.from) {
28525                         turnPath = turnPath.slice(i);
28526                         break;
28527                       }
28528                     }
28529                   }
28530
28531                   var turn = pathToTurn(turnPath);
28532
28533                   if (turn) {
28534                     if (matchedRestriction) {
28535                       turn.restrictionID = matchedRestriction.id;
28536                       turn.no = matchedRestriction.no;
28537                       turn.only = matchedRestriction.only;
28538                       turn.direct = matchedRestriction.direct;
28539                     }
28540
28541                     turns.push(osmTurn(turn));
28542                   }
28543
28544                   if (currPath[0] === currPath[2]) return; // if we made a u-turn - stop here
28545                 }
28546
28547                 if (matchedRestriction && matchedRestriction.end) return; // don't advance any further
28548                 // which nodes can we step into?
28549
28550                 var n1 = vgraph.entity(entity.first());
28551                 var n2 = vgraph.entity(entity.last());
28552                 var dist = geoSphericalDistance(n1.loc, n2.loc);
28553                 var nextNodes = [];
28554
28555                 if (currPath.length > 1) {
28556                   if (dist > maxDistance) return; // the next node is too far
28557
28558                   if (!entity.__via) return; // this way is a leaf / can't be a via
28559                 }
28560
28561                 if (!entity.__oneWay && // bidirectional..
28562                 keyVertexIds.indexOf(n1.id) !== -1 && // key vertex..
28563                 currPath.indexOf(n1.id) === -1) {
28564                   // haven't seen it yet..
28565                   nextNodes.push(n1); // can advance to first node
28566                 }
28567
28568                 if (keyVertexIds.indexOf(n2.id) !== -1 && // key vertex..
28569                 currPath.indexOf(n2.id) === -1) {
28570                   // haven't seen it yet..
28571                   nextNodes.push(n2); // can advance to last node
28572                 }
28573
28574                 nextNodes.forEach(function (nextNode) {
28575                   // gather restrictions FROM this way
28576                   var fromRestrictions = vgraph.parentRelations(entity).filter(function (r) {
28577                     if (!r.isRestriction()) return false;
28578                     var f = r.memberByRole('from');
28579                     if (!f || f.id !== entity.id) return false;
28580                     var isOnly = /^only_/.test(r.tags.restriction);
28581                     if (!isOnly) return true; // `only_` restrictions only matter along the direction of the VIA - #4849
28582
28583                     var isOnlyVia = false;
28584                     var v = r.membersByRole('via');
28585
28586                     if (v.length === 1 && v[0].type === 'node') {
28587                       // via node
28588                       isOnlyVia = v[0].id === nextNode.id;
28589                     } else {
28590                       // via way(s)
28591                       for (var i = 0; i < v.length; i++) {
28592                         if (v[i].type !== 'way') continue;
28593                         var viaWay = vgraph.entity(v[i].id);
28594
28595                         if (viaWay.first() === nextNode.id || viaWay.last() === nextNode.id) {
28596                           isOnlyVia = true;
28597                           break;
28598                         }
28599                       }
28600                     }
28601
28602                     return isOnlyVia;
28603                   });
28604                   step(nextNode, currPath, currRestrictions.concat(fromRestrictions), false);
28605                 });
28606               }
28607             } // assumes path is alternating way-node-way of odd length
28608
28609
28610             function pathToTurn(path) {
28611               if (path.length < 3) return;
28612               var fromWayId, fromNodeId, fromVertexId;
28613               var toWayId, toNodeId, toVertexId;
28614               var viaWayIds, viaNodeId, isUturn;
28615               fromWayId = path[0];
28616               toWayId = path[path.length - 1];
28617
28618               if (path.length === 3 && fromWayId === toWayId) {
28619                 // u turn
28620                 var way = vgraph.entity(fromWayId);
28621                 if (way.__oneWay) return null;
28622                 isUturn = true;
28623                 viaNodeId = fromVertexId = toVertexId = path[1];
28624                 fromNodeId = toNodeId = adjacentNode(fromWayId, viaNodeId);
28625               } else {
28626                 isUturn = false;
28627                 fromVertexId = path[1];
28628                 fromNodeId = adjacentNode(fromWayId, fromVertexId);
28629                 toVertexId = path[path.length - 2];
28630                 toNodeId = adjacentNode(toWayId, toVertexId);
28631
28632                 if (path.length === 3) {
28633                   viaNodeId = path[1];
28634                 } else {
28635                   viaWayIds = path.filter(function (entityId) {
28636                     return entityId[0] === 'w';
28637                   });
28638                   viaWayIds = viaWayIds.slice(1, viaWayIds.length - 1); // remove first, last
28639                 }
28640               }
28641
28642               return {
28643                 key: path.join('_'),
28644                 path: path,
28645                 from: {
28646                   node: fromNodeId,
28647                   way: fromWayId,
28648                   vertex: fromVertexId
28649                 },
28650                 via: {
28651                   node: viaNodeId,
28652                   ways: viaWayIds
28653                 },
28654                 to: {
28655                   node: toNodeId,
28656                   way: toWayId,
28657                   vertex: toVertexId
28658                 },
28659                 u: isUturn
28660               };
28661
28662               function adjacentNode(wayId, affixId) {
28663                 var nodes = vgraph.entity(wayId).nodes;
28664                 return affixId === nodes[0] ? nodes[1] : nodes[nodes.length - 2];
28665               }
28666             }
28667           };
28668
28669           return intersection;
28670         }
28671         function osmInferRestriction(graph, turn, projection) {
28672           var fromWay = graph.entity(turn.from.way);
28673           var fromNode = graph.entity(turn.from.node);
28674           var fromVertex = graph.entity(turn.from.vertex);
28675           var toWay = graph.entity(turn.to.way);
28676           var toNode = graph.entity(turn.to.node);
28677           var toVertex = graph.entity(turn.to.vertex);
28678           var fromOneWay = fromWay.tags.oneway === 'yes';
28679           var toOneWay = toWay.tags.oneway === 'yes';
28680           var angle = (geoAngle(fromVertex, fromNode, projection) - geoAngle(toVertex, toNode, projection)) * 180 / Math.PI;
28681
28682           while (angle < 0) {
28683             angle += 360;
28684           }
28685
28686           if (fromNode === toNode) return 'no_u_turn';
28687           if ((angle < 23 || angle > 336) && fromOneWay && toOneWay) return 'no_u_turn'; // wider tolerance for u-turn if both ways are oneway
28688
28689           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)
28690
28691           if (angle < 158) return 'no_right_turn';
28692           if (angle > 202) return 'no_left_turn';
28693           return 'no_straight_on';
28694         }
28695
28696         function actionMergePolygon(ids, newRelationId) {
28697           function groupEntities(graph) {
28698             var entities = ids.map(function (id) {
28699               return graph.entity(id);
28700             });
28701             var geometryGroups = utilArrayGroupBy(entities, function (entity) {
28702               if (entity.type === 'way' && entity.isClosed()) {
28703                 return 'closedWay';
28704               } else if (entity.type === 'relation' && entity.isMultipolygon()) {
28705                 return 'multipolygon';
28706               } else {
28707                 return 'other';
28708               }
28709             });
28710             return Object.assign({
28711               closedWay: [],
28712               multipolygon: [],
28713               other: []
28714             }, geometryGroups);
28715           }
28716
28717           var action = function action(graph) {
28718             var entities = groupEntities(graph); // An array representing all the polygons that are part of the multipolygon.
28719             //
28720             // Each element is itself an array of objects with an id property, and has a
28721             // locs property which is an array of the locations forming the polygon.
28722
28723             var polygons = entities.multipolygon.reduce(function (polygons, m) {
28724               return polygons.concat(osmJoinWays(m.members, graph));
28725             }, []).concat(entities.closedWay.map(function (d) {
28726               var member = [{
28727                 id: d.id
28728               }];
28729               member.nodes = graph.childNodes(d);
28730               return member;
28731             })); // contained is an array of arrays of boolean values,
28732             // where contained[j][k] is true iff the jth way is
28733             // contained by the kth way.
28734
28735             var contained = polygons.map(function (w, i) {
28736               return polygons.map(function (d, n) {
28737                 if (i === n) return null;
28738                 return geoPolygonContainsPolygon(d.nodes.map(function (n) {
28739                   return n.loc;
28740                 }), w.nodes.map(function (n) {
28741                   return n.loc;
28742                 }));
28743               });
28744             }); // Sort all polygons as either outer or inner ways
28745
28746             var members = [];
28747             var outer = true;
28748
28749             while (polygons.length) {
28750               extractUncontained(polygons);
28751               polygons = polygons.filter(isContained);
28752               contained = contained.filter(isContained).map(filterContained);
28753             }
28754
28755             function isContained(d, i) {
28756               return contained[i].some(function (val) {
28757                 return val;
28758               });
28759             }
28760
28761             function filterContained(d) {
28762               return d.filter(isContained);
28763             }
28764
28765             function extractUncontained(polygons) {
28766               polygons.forEach(function (d, i) {
28767                 if (!isContained(d, i)) {
28768                   d.forEach(function (member) {
28769                     members.push({
28770                       type: 'way',
28771                       id: member.id,
28772                       role: outer ? 'outer' : 'inner'
28773                     });
28774                   });
28775                 }
28776               });
28777               outer = !outer;
28778             } // Move all tags to one relation
28779
28780
28781             var relation = entities.multipolygon[0] || osmRelation({
28782               id: newRelationId,
28783               tags: {
28784                 type: 'multipolygon'
28785               }
28786             });
28787             entities.multipolygon.slice(1).forEach(function (m) {
28788               relation = relation.mergeTags(m.tags);
28789               graph = graph.remove(m);
28790             });
28791             entities.closedWay.forEach(function (way) {
28792               function isThisOuter(m) {
28793                 return m.id === way.id && m.role !== 'inner';
28794               }
28795
28796               if (members.some(isThisOuter)) {
28797                 relation = relation.mergeTags(way.tags);
28798                 graph = graph.replace(way.update({
28799                   tags: {}
28800                 }));
28801               }
28802             });
28803             return graph.replace(relation.update({
28804               members: members,
28805               tags: utilObjectOmit(relation.tags, ['area'])
28806             }));
28807           };
28808
28809           action.disabled = function (graph) {
28810             var entities = groupEntities(graph);
28811
28812             if (entities.other.length > 0 || entities.closedWay.length + entities.multipolygon.length < 2) {
28813               return 'not_eligible';
28814             }
28815
28816             if (!entities.multipolygon.every(function (r) {
28817               return r.isComplete(graph);
28818             })) {
28819               return 'incomplete_relation';
28820             }
28821
28822             if (!entities.multipolygon.length) {
28823               var sharedMultipolygons = [];
28824               entities.closedWay.forEach(function (way, i) {
28825                 if (i === 0) {
28826                   sharedMultipolygons = graph.parentMultipolygons(way);
28827                 } else {
28828                   sharedMultipolygons = utilArrayIntersection(sharedMultipolygons, graph.parentMultipolygons(way));
28829                 }
28830               });
28831               sharedMultipolygons = sharedMultipolygons.filter(function (relation) {
28832                 return relation.members.length === entities.closedWay.length;
28833               });
28834
28835               if (sharedMultipolygons.length) {
28836                 // don't create a new multipolygon if it'd be redundant
28837                 return 'not_eligible';
28838               }
28839             } else if (entities.closedWay.some(function (way) {
28840               return utilArrayIntersection(graph.parentMultipolygons(way), entities.multipolygon).length;
28841             })) {
28842               // don't add a way to a multipolygon again if it's already a member
28843               return 'not_eligible';
28844             }
28845           };
28846
28847           return action;
28848         }
28849
28850         var UNSUPPORTED_Y$3 = regexpStickyHelpers.UNSUPPORTED_Y;
28851
28852         // `RegExp.prototype.flags` getter
28853         // https://tc39.github.io/ecma262/#sec-get-regexp.prototype.flags
28854         if (descriptors && (/./g.flags != 'g' || UNSUPPORTED_Y$3)) {
28855           objectDefineProperty.f(RegExp.prototype, 'flags', {
28856             configurable: true,
28857             get: regexpFlags
28858           });
28859         }
28860
28861         var fastDeepEqual = function equal(a, b) {
28862           if (a === b) return true;
28863
28864           if (a && b && _typeof(a) == 'object' && _typeof(b) == 'object') {
28865             if (a.constructor !== b.constructor) return false;
28866             var length, i, keys;
28867
28868             if (Array.isArray(a)) {
28869               length = a.length;
28870               if (length != b.length) return false;
28871
28872               for (i = length; i-- !== 0;) {
28873                 if (!equal(a[i], b[i])) return false;
28874               }
28875
28876               return true;
28877             }
28878
28879             if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
28880             if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
28881             if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
28882             keys = Object.keys(a);
28883             length = keys.length;
28884             if (length !== Object.keys(b).length) return false;
28885
28886             for (i = length; i-- !== 0;) {
28887               if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
28888             }
28889
28890             for (i = length; i-- !== 0;) {
28891               var key = keys[i];
28892               if (!equal(a[key], b[key])) return false;
28893             }
28894
28895             return true;
28896           } // true if both NaN, false otherwise
28897
28898
28899           return a !== a && b !== b;
28900         };
28901
28902         // J. W. Hunt and M. D. McIlroy, An algorithm for differential buffer
28903         // comparison, Bell Telephone Laboratories CSTR #41 (1976)
28904         // http://www.cs.dartmouth.edu/~doug/
28905         // https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
28906         //
28907         // Expects two arrays, finds longest common sequence
28908
28909         function LCS(buffer1, buffer2) {
28910           var equivalenceClasses = {};
28911
28912           for (var j = 0; j < buffer2.length; j++) {
28913             var item = buffer2[j];
28914
28915             if (equivalenceClasses[item]) {
28916               equivalenceClasses[item].push(j);
28917             } else {
28918               equivalenceClasses[item] = [j];
28919             }
28920           }
28921
28922           var NULLRESULT = {
28923             buffer1index: -1,
28924             buffer2index: -1,
28925             chain: null
28926           };
28927           var candidates = [NULLRESULT];
28928
28929           for (var i = 0; i < buffer1.length; i++) {
28930             var _item = buffer1[i];
28931             var buffer2indices = equivalenceClasses[_item] || [];
28932             var r = 0;
28933             var c = candidates[0];
28934
28935             for (var jx = 0; jx < buffer2indices.length; jx++) {
28936               var _j = buffer2indices[jx];
28937               var s = void 0;
28938
28939               for (s = r; s < candidates.length; s++) {
28940                 if (candidates[s].buffer2index < _j && (s === candidates.length - 1 || candidates[s + 1].buffer2index > _j)) {
28941                   break;
28942                 }
28943               }
28944
28945               if (s < candidates.length) {
28946                 var newCandidate = {
28947                   buffer1index: i,
28948                   buffer2index: _j,
28949                   chain: candidates[s]
28950                 };
28951
28952                 if (r === candidates.length) {
28953                   candidates.push(c);
28954                 } else {
28955                   candidates[r] = c;
28956                 }
28957
28958                 r = s + 1;
28959                 c = newCandidate;
28960
28961                 if (r === candidates.length) {
28962                   break; // no point in examining further (j)s
28963                 }
28964               }
28965             }
28966
28967             candidates[r] = c;
28968           } // At this point, we know the LCS: it's in the reverse of the
28969           // linked-list through .chain of candidates[candidates.length - 1].
28970
28971
28972           return candidates[candidates.length - 1];
28973         } // We apply the LCS to build a 'comm'-style picture of the
28974         // offsets and lengths of mismatched chunks in the input
28975         // buffers. This is used by diff3MergeRegions.
28976
28977
28978         function diffIndices(buffer1, buffer2) {
28979           var lcs = LCS(buffer1, buffer2);
28980           var result = [];
28981           var tail1 = buffer1.length;
28982           var tail2 = buffer2.length;
28983
28984           for (var candidate = lcs; candidate !== null; candidate = candidate.chain) {
28985             var mismatchLength1 = tail1 - candidate.buffer1index - 1;
28986             var mismatchLength2 = tail2 - candidate.buffer2index - 1;
28987             tail1 = candidate.buffer1index;
28988             tail2 = candidate.buffer2index;
28989
28990             if (mismatchLength1 || mismatchLength2) {
28991               result.push({
28992                 buffer1: [tail1 + 1, mismatchLength1],
28993                 buffer1Content: buffer1.slice(tail1 + 1, tail1 + 1 + mismatchLength1),
28994                 buffer2: [tail2 + 1, mismatchLength2],
28995                 buffer2Content: buffer2.slice(tail2 + 1, tail2 + 1 + mismatchLength2)
28996               });
28997             }
28998           }
28999
29000           result.reverse();
29001           return result;
29002         } // We apply the LCS to build a JSON representation of a
29003         // independently derived from O, returns a fairly complicated
29004         // internal representation of merge decisions it's taken. The
29005         // interested reader may wish to consult
29006         //
29007         // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce.
29008         // 'A Formal Investigation of ' In Arvind and Prasad,
29009         // editors, Foundations of Software Technology and Theoretical
29010         // Computer Science (FSTTCS), December 2007.
29011         //
29012         // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
29013         //
29014
29015
29016         function diff3MergeRegions(a, o, b) {
29017           // "hunks" are array subsets where `a` or `b` are different from `o`
29018           // https://www.gnu.org/software/diffutils/manual/html_node/diff3-Hunks.html
29019           var hunks = [];
29020
29021           function addHunk(h, ab) {
29022             hunks.push({
29023               ab: ab,
29024               oStart: h.buffer1[0],
29025               oLength: h.buffer1[1],
29026               // length of o to remove
29027               abStart: h.buffer2[0],
29028               abLength: h.buffer2[1] // length of a/b to insert
29029               // abContent: (ab === 'a' ? a : b).slice(h.buffer2[0], h.buffer2[0] + h.buffer2[1])
29030
29031             });
29032           }
29033
29034           diffIndices(o, a).forEach(function (item) {
29035             return addHunk(item, 'a');
29036           });
29037           diffIndices(o, b).forEach(function (item) {
29038             return addHunk(item, 'b');
29039           });
29040           hunks.sort(function (x, y) {
29041             return x.oStart - y.oStart;
29042           });
29043           var results = [];
29044           var currOffset = 0;
29045
29046           function advanceTo(endOffset) {
29047             if (endOffset > currOffset) {
29048               results.push({
29049                 stable: true,
29050                 buffer: 'o',
29051                 bufferStart: currOffset,
29052                 bufferLength: endOffset - currOffset,
29053                 bufferContent: o.slice(currOffset, endOffset)
29054               });
29055               currOffset = endOffset;
29056             }
29057           }
29058
29059           while (hunks.length) {
29060             var hunk = hunks.shift();
29061             var regionStart = hunk.oStart;
29062             var regionEnd = hunk.oStart + hunk.oLength;
29063             var regionHunks = [hunk];
29064             advanceTo(regionStart); // Try to pull next overlapping hunk into this region
29065
29066             while (hunks.length) {
29067               var nextHunk = hunks[0];
29068               var nextHunkStart = nextHunk.oStart;
29069               if (nextHunkStart > regionEnd) break; // no overlap
29070
29071               regionEnd = Math.max(regionEnd, nextHunkStart + nextHunk.oLength);
29072               regionHunks.push(hunks.shift());
29073             }
29074
29075             if (regionHunks.length === 1) {
29076               // Only one hunk touches this region, meaning that there is no conflict here.
29077               // Either `a` or `b` is inserting into a region of `o` unchanged by the other.
29078               if (hunk.abLength > 0) {
29079                 var buffer = hunk.ab === 'a' ? a : b;
29080                 results.push({
29081                   stable: true,
29082                   buffer: hunk.ab,
29083                   bufferStart: hunk.abStart,
29084                   bufferLength: hunk.abLength,
29085                   bufferContent: buffer.slice(hunk.abStart, hunk.abStart + hunk.abLength)
29086                 });
29087               }
29088             } else {
29089               // A true a/b conflict. Determine the bounds involved from `a`, `o`, and `b`.
29090               // Effectively merge all the `a` hunks into one giant hunk, then do the
29091               // same for the `b` hunks; then, correct for skew in the regions of `o`
29092               // that each side changed, and report appropriate spans for the three sides.
29093               var bounds = {
29094                 a: [a.length, -1, o.length, -1],
29095                 b: [b.length, -1, o.length, -1]
29096               };
29097
29098               while (regionHunks.length) {
29099                 hunk = regionHunks.shift();
29100                 var oStart = hunk.oStart;
29101                 var oEnd = oStart + hunk.oLength;
29102                 var abStart = hunk.abStart;
29103                 var abEnd = abStart + hunk.abLength;
29104                 var _b = bounds[hunk.ab];
29105                 _b[0] = Math.min(abStart, _b[0]);
29106                 _b[1] = Math.max(abEnd, _b[1]);
29107                 _b[2] = Math.min(oStart, _b[2]);
29108                 _b[3] = Math.max(oEnd, _b[3]);
29109               }
29110
29111               var aStart = bounds.a[0] + (regionStart - bounds.a[2]);
29112               var aEnd = bounds.a[1] + (regionEnd - bounds.a[3]);
29113               var bStart = bounds.b[0] + (regionStart - bounds.b[2]);
29114               var bEnd = bounds.b[1] + (regionEnd - bounds.b[3]);
29115               var result = {
29116                 stable: false,
29117                 aStart: aStart,
29118                 aLength: aEnd - aStart,
29119                 aContent: a.slice(aStart, aEnd),
29120                 oStart: regionStart,
29121                 oLength: regionEnd - regionStart,
29122                 oContent: o.slice(regionStart, regionEnd),
29123                 bStart: bStart,
29124                 bLength: bEnd - bStart,
29125                 bContent: b.slice(bStart, bEnd)
29126               };
29127               results.push(result);
29128             }
29129
29130             currOffset = regionEnd;
29131           }
29132
29133           advanceTo(o.length);
29134           return results;
29135         } // Applies the output of diff3MergeRegions to actually
29136         // construct the merged buffer; the returned result alternates
29137         // between 'ok' and 'conflict' blocks.
29138         // A "false conflict" is where `a` and `b` both change the same from `o`
29139
29140
29141         function diff3Merge(a, o, b, options) {
29142           var defaults = {
29143             excludeFalseConflicts: true,
29144             stringSeparator: /\s+/
29145           };
29146           options = Object.assign(defaults, options);
29147           var aString = typeof a === 'string';
29148           var oString = typeof o === 'string';
29149           var bString = typeof b === 'string';
29150           if (aString) a = a.split(options.stringSeparator);
29151           if (oString) o = o.split(options.stringSeparator);
29152           if (bString) b = b.split(options.stringSeparator);
29153           var results = [];
29154           var regions = diff3MergeRegions(a, o, b);
29155           var okBuffer = [];
29156
29157           function flushOk() {
29158             if (okBuffer.length) {
29159               results.push({
29160                 ok: okBuffer
29161               });
29162             }
29163
29164             okBuffer = [];
29165           }
29166
29167           function isFalseConflict(a, b) {
29168             if (a.length !== b.length) return false;
29169
29170             for (var i = 0; i < a.length; i++) {
29171               if (a[i] !== b[i]) return false;
29172             }
29173
29174             return true;
29175           }
29176
29177           regions.forEach(function (region) {
29178             if (region.stable) {
29179               var _okBuffer;
29180
29181               (_okBuffer = okBuffer).push.apply(_okBuffer, _toConsumableArray(region.bufferContent));
29182             } else {
29183               if (options.excludeFalseConflicts && isFalseConflict(region.aContent, region.bContent)) {
29184                 var _okBuffer2;
29185
29186                 (_okBuffer2 = okBuffer).push.apply(_okBuffer2, _toConsumableArray(region.aContent));
29187               } else {
29188                 flushOk();
29189                 results.push({
29190                   conflict: {
29191                     a: region.aContent,
29192                     aIndex: region.aStart,
29193                     o: region.oContent,
29194                     oIndex: region.oStart,
29195                     b: region.bContent,
29196                     bIndex: region.bStart
29197                   }
29198                 });
29199               }
29200             }
29201           });
29202           flushOk();
29203           return results;
29204         }
29205
29206         function actionMergeRemoteChanges(id, localGraph, remoteGraph, discardTags, formatUser) {
29207           discardTags = discardTags || {};
29208           var _option = 'safe'; // 'safe', 'force_local', 'force_remote'
29209
29210           var _conflicts = [];
29211
29212           function user(d) {
29213             return typeof formatUser === 'function' ? formatUser(d) : d;
29214           }
29215
29216           function mergeLocation(remote, target) {
29217             function pointEqual(a, b) {
29218               var epsilon = 1e-6;
29219               return Math.abs(a[0] - b[0]) < epsilon && Math.abs(a[1] - b[1]) < epsilon;
29220             }
29221
29222             if (_option === 'force_local' || pointEqual(target.loc, remote.loc)) {
29223               return target;
29224             }
29225
29226             if (_option === 'force_remote') {
29227               return target.update({
29228                 loc: remote.loc
29229               });
29230             }
29231
29232             _conflicts.push(_t('merge_remote_changes.conflict.location', {
29233               user: user(remote.user)
29234             }));
29235
29236             return target;
29237           }
29238
29239           function mergeNodes(base, remote, target) {
29240             if (_option === 'force_local' || fastDeepEqual(target.nodes, remote.nodes)) {
29241               return target;
29242             }
29243
29244             if (_option === 'force_remote') {
29245               return target.update({
29246                 nodes: remote.nodes
29247               });
29248             }
29249
29250             var ccount = _conflicts.length;
29251             var o = base.nodes || [];
29252             var a = target.nodes || [];
29253             var b = remote.nodes || [];
29254             var nodes = [];
29255             var hunks = diff3Merge(a, o, b, {
29256               excludeFalseConflicts: true
29257             });
29258
29259             for (var i = 0; i < hunks.length; i++) {
29260               var hunk = hunks[i];
29261
29262               if (hunk.ok) {
29263                 nodes.push.apply(nodes, hunk.ok);
29264               } else {
29265                 // for all conflicts, we can assume c.a !== c.b
29266                 // because `diff3Merge` called with `true` option to exclude false conflicts..
29267                 var c = hunk.conflict;
29268
29269                 if (fastDeepEqual(c.o, c.a)) {
29270                   // only changed remotely
29271                   nodes.push.apply(nodes, c.b);
29272                 } else if (fastDeepEqual(c.o, c.b)) {
29273                   // only changed locally
29274                   nodes.push.apply(nodes, c.a);
29275                 } else {
29276                   // changed both locally and remotely
29277                   _conflicts.push(_t('merge_remote_changes.conflict.nodelist', {
29278                     user: user(remote.user)
29279                   }));
29280
29281                   break;
29282                 }
29283               }
29284             }
29285
29286             return _conflicts.length === ccount ? target.update({
29287               nodes: nodes
29288             }) : target;
29289           }
29290
29291           function mergeChildren(targetWay, children, updates, graph) {
29292             function isUsed(node, targetWay) {
29293               var hasInterestingParent = graph.parentWays(node).some(function (way) {
29294                 return way.id !== targetWay.id;
29295               });
29296               return node.hasInterestingTags() || hasInterestingParent || graph.parentRelations(node).length > 0;
29297             }
29298
29299             var ccount = _conflicts.length;
29300
29301             for (var i = 0; i < children.length; i++) {
29302               var id = children[i];
29303               var node = graph.hasEntity(id); // remove unused childNodes..
29304
29305               if (targetWay.nodes.indexOf(id) === -1) {
29306                 if (node && !isUsed(node, targetWay)) {
29307                   updates.removeIds.push(id);
29308                 }
29309
29310                 continue;
29311               } // restore used childNodes..
29312
29313
29314               var local = localGraph.hasEntity(id);
29315               var remote = remoteGraph.hasEntity(id);
29316               var target;
29317
29318               if (_option === 'force_remote' && remote && remote.visible) {
29319                 updates.replacements.push(remote);
29320               } else if (_option === 'force_local' && local) {
29321                 target = osmEntity(local);
29322
29323                 if (remote) {
29324                   target = target.update({
29325                     version: remote.version
29326                   });
29327                 }
29328
29329                 updates.replacements.push(target);
29330               } else if (_option === 'safe' && local && remote && local.version !== remote.version) {
29331                 target = osmEntity(local, {
29332                   version: remote.version
29333                 });
29334
29335                 if (remote.visible) {
29336                   target = mergeLocation(remote, target);
29337                 } else {
29338                   _conflicts.push(_t('merge_remote_changes.conflict.deleted', {
29339                     user: user(remote.user)
29340                   }));
29341                 }
29342
29343                 if (_conflicts.length !== ccount) break;
29344                 updates.replacements.push(target);
29345               }
29346             }
29347
29348             return targetWay;
29349           }
29350
29351           function updateChildren(updates, graph) {
29352             for (var i = 0; i < updates.replacements.length; i++) {
29353               graph = graph.replace(updates.replacements[i]);
29354             }
29355
29356             if (updates.removeIds.length) {
29357               graph = actionDeleteMultiple(updates.removeIds)(graph);
29358             }
29359
29360             return graph;
29361           }
29362
29363           function mergeMembers(remote, target) {
29364             if (_option === 'force_local' || fastDeepEqual(target.members, remote.members)) {
29365               return target;
29366             }
29367
29368             if (_option === 'force_remote') {
29369               return target.update({
29370                 members: remote.members
29371               });
29372             }
29373
29374             _conflicts.push(_t('merge_remote_changes.conflict.memberlist', {
29375               user: user(remote.user)
29376             }));
29377
29378             return target;
29379           }
29380
29381           function mergeTags(base, remote, target) {
29382             if (_option === 'force_local' || fastDeepEqual(target.tags, remote.tags)) {
29383               return target;
29384             }
29385
29386             if (_option === 'force_remote') {
29387               return target.update({
29388                 tags: remote.tags
29389               });
29390             }
29391
29392             var ccount = _conflicts.length;
29393             var o = base.tags || {};
29394             var a = target.tags || {};
29395             var b = remote.tags || {};
29396             var keys = utilArrayUnion(utilArrayUnion(Object.keys(o), Object.keys(a)), Object.keys(b)).filter(function (k) {
29397               return !discardTags[k];
29398             });
29399             var tags = Object.assign({}, a); // shallow copy
29400
29401             var changed = false;
29402
29403             for (var i = 0; i < keys.length; i++) {
29404               var k = keys[i];
29405
29406               if (o[k] !== b[k] && a[k] !== b[k]) {
29407                 // changed remotely..
29408                 if (o[k] !== a[k]) {
29409                   // changed locally..
29410                   _conflicts.push(_t('merge_remote_changes.conflict.tags', {
29411                     tag: k,
29412                     local: a[k],
29413                     remote: b[k],
29414                     user: user(remote.user)
29415                   }));
29416                 } else {
29417                   // unchanged locally, accept remote change..
29418                   if (b.hasOwnProperty(k)) {
29419                     tags[k] = b[k];
29420                   } else {
29421                     delete tags[k];
29422                   }
29423
29424                   changed = true;
29425                 }
29426               }
29427             }
29428
29429             return changed && _conflicts.length === ccount ? target.update({
29430               tags: tags
29431             }) : target;
29432           } //  `graph.base()` is the common ancestor of the two graphs.
29433           //  `localGraph` contains user's edits up to saving
29434           //  `remoteGraph` contains remote edits to modified nodes
29435           //  `graph` must be a descendent of `localGraph` and may include
29436           //      some conflict resolution actions performed on it.
29437           //
29438           //                  --- ... --- `localGraph` -- ... -- `graph`
29439           //                 /
29440           //  `graph.base()` --- ... --- `remoteGraph`
29441           //
29442
29443
29444           var action = function action(graph) {
29445             var updates = {
29446               replacements: [],
29447               removeIds: []
29448             };
29449             var base = graph.base().entities[id];
29450             var local = localGraph.entity(id);
29451             var remote = remoteGraph.entity(id);
29452             var target = osmEntity(local, {
29453               version: remote.version
29454             }); // delete/undelete
29455
29456             if (!remote.visible) {
29457               if (_option === 'force_remote') {
29458                 return actionDeleteMultiple([id])(graph);
29459               } else if (_option === 'force_local') {
29460                 if (target.type === 'way') {
29461                   target = mergeChildren(target, utilArrayUniq(local.nodes), updates, graph);
29462                   graph = updateChildren(updates, graph);
29463                 }
29464
29465                 return graph.replace(target);
29466               } else {
29467                 _conflicts.push(_t('merge_remote_changes.conflict.deleted', {
29468                   user: user(remote.user)
29469                 }));
29470
29471                 return graph; // do nothing
29472               }
29473             } // merge
29474
29475
29476             if (target.type === 'node') {
29477               target = mergeLocation(remote, target);
29478             } else if (target.type === 'way') {
29479               // pull in any child nodes that may not be present locally..
29480               graph.rebase(remoteGraph.childNodes(remote), [graph], false);
29481               target = mergeNodes(base, remote, target);
29482               target = mergeChildren(target, utilArrayUnion(local.nodes, remote.nodes), updates, graph);
29483             } else if (target.type === 'relation') {
29484               target = mergeMembers(remote, target);
29485             }
29486
29487             target = mergeTags(base, remote, target);
29488
29489             if (!_conflicts.length) {
29490               graph = updateChildren(updates, graph).replace(target);
29491             }
29492
29493             return graph;
29494           };
29495
29496           action.withOption = function (opt) {
29497             _option = opt;
29498             return action;
29499           };
29500
29501           action.conflicts = function () {
29502             return _conflicts;
29503           };
29504
29505           return action;
29506         }
29507
29508         // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
29509
29510         function actionMove(moveIDs, tryDelta, projection, cache) {
29511           var _delta = tryDelta;
29512
29513           function setupCache(graph) {
29514             function canMove(nodeID) {
29515               // Allow movement of any node that is in the selectedIDs list..
29516               if (moveIDs.indexOf(nodeID) !== -1) return true; // Allow movement of a vertex where 2 ways meet..
29517
29518               var parents = graph.parentWays(graph.entity(nodeID));
29519               if (parents.length < 3) return true; // Restrict movement of a vertex where >2 ways meet, unless all parentWays are moving too..
29520
29521               var parentsMoving = parents.every(function (way) {
29522                 return cache.moving[way.id];
29523               });
29524               if (!parentsMoving) delete cache.moving[nodeID];
29525               return parentsMoving;
29526             }
29527
29528             function cacheEntities(ids) {
29529               for (var i = 0; i < ids.length; i++) {
29530                 var id = ids[i];
29531                 if (cache.moving[id]) continue;
29532                 cache.moving[id] = true;
29533                 var entity = graph.hasEntity(id);
29534                 if (!entity) continue;
29535
29536                 if (entity.type === 'node') {
29537                   cache.nodes.push(id);
29538                   cache.startLoc[id] = entity.loc;
29539                 } else if (entity.type === 'way') {
29540                   cache.ways.push(id);
29541                   cacheEntities(entity.nodes);
29542                 } else {
29543                   cacheEntities(entity.members.map(function (member) {
29544                     return member.id;
29545                   }));
29546                 }
29547               }
29548             }
29549
29550             function cacheIntersections(ids) {
29551               function isEndpoint(way, id) {
29552                 return !way.isClosed() && !!way.affix(id);
29553               }
29554
29555               for (var i = 0; i < ids.length; i++) {
29556                 var id = ids[i]; // consider only intersections with 1 moved and 1 unmoved way.
29557
29558                 var childNodes = graph.childNodes(graph.entity(id));
29559
29560                 for (var j = 0; j < childNodes.length; j++) {
29561                   var node = childNodes[j];
29562                   var parents = graph.parentWays(node);
29563                   if (parents.length !== 2) continue;
29564                   var moved = graph.entity(id);
29565                   var unmoved = null;
29566
29567                   for (var k = 0; k < parents.length; k++) {
29568                     var way = parents[k];
29569
29570                     if (!cache.moving[way.id]) {
29571                       unmoved = way;
29572                       break;
29573                     }
29574                   }
29575
29576                   if (!unmoved) continue; // exclude ways that are overly connected..
29577
29578                   if (utilArrayIntersection(moved.nodes, unmoved.nodes).length > 2) continue;
29579                   if (moved.isArea() || unmoved.isArea()) continue;
29580                   cache.intersections.push({
29581                     nodeId: node.id,
29582                     movedId: moved.id,
29583                     unmovedId: unmoved.id,
29584                     movedIsEP: isEndpoint(moved, node.id),
29585                     unmovedIsEP: isEndpoint(unmoved, node.id)
29586                   });
29587                 }
29588               }
29589             }
29590
29591             if (!cache) {
29592               cache = {};
29593             }
29594
29595             if (!cache.ok) {
29596               cache.moving = {};
29597               cache.intersections = [];
29598               cache.replacedVertex = {};
29599               cache.startLoc = {};
29600               cache.nodes = [];
29601               cache.ways = [];
29602               cacheEntities(moveIDs);
29603               cacheIntersections(cache.ways);
29604               cache.nodes = cache.nodes.filter(canMove);
29605               cache.ok = true;
29606             }
29607           } // Place a vertex where the moved vertex used to be, to preserve way shape..
29608           //
29609           //  Start:
29610           //      b ---- e
29611           //     / \
29612           //    /   \
29613           //   /     \
29614           //  a       c
29615           //
29616           //      *               node '*' added to preserve shape
29617           //     / \
29618           //    /   b ---- e      way `b,e` moved here:
29619           //   /     \
29620           //  a       c
29621           //
29622           //
29623
29624
29625           function replaceMovedVertex(nodeId, wayId, graph, delta) {
29626             var way = graph.entity(wayId);
29627             var moved = graph.entity(nodeId);
29628             var movedIndex = way.nodes.indexOf(nodeId);
29629             var len, prevIndex, nextIndex;
29630
29631             if (way.isClosed()) {
29632               len = way.nodes.length - 1;
29633               prevIndex = (movedIndex + len - 1) % len;
29634               nextIndex = (movedIndex + len + 1) % len;
29635             } else {
29636               len = way.nodes.length;
29637               prevIndex = movedIndex - 1;
29638               nextIndex = movedIndex + 1;
29639             }
29640
29641             var prev = graph.hasEntity(way.nodes[prevIndex]);
29642             var next = graph.hasEntity(way.nodes[nextIndex]); // Don't add orig vertex at endpoint..
29643
29644             if (!prev || !next) return graph;
29645             var key = wayId + '_' + nodeId;
29646             var orig = cache.replacedVertex[key];
29647
29648             if (!orig) {
29649               orig = osmNode();
29650               cache.replacedVertex[key] = orig;
29651               cache.startLoc[orig.id] = cache.startLoc[nodeId];
29652             }
29653
29654             var start, end;
29655
29656             if (delta) {
29657               start = projection(cache.startLoc[nodeId]);
29658               end = projection.invert(geoVecAdd(start, delta));
29659             } else {
29660               end = cache.startLoc[nodeId];
29661             }
29662
29663             orig = orig.move(end);
29664             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..
29665
29666             if (angle > 175 && angle < 185) return graph; // moving forward or backward along way?
29667
29668             var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection);
29669             var p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection);
29670             var d1 = geoPathLength(p1);
29671             var d2 = geoPathLength(p2);
29672             var insertAt = d1 <= d2 ? movedIndex : nextIndex; // moving around closed loop?
29673
29674             if (way.isClosed() && insertAt === 0) insertAt = len;
29675             way = way.addNode(orig.id, insertAt);
29676             return graph.replace(orig).replace(way);
29677           } // Remove duplicate vertex that might have been added by
29678           // replaceMovedVertex.  This is done after the unzorro checks.
29679
29680
29681           function removeDuplicateVertices(wayId, graph) {
29682             var way = graph.entity(wayId);
29683             var epsilon = 1e-6;
29684             var prev, curr;
29685
29686             function isInteresting(node, graph) {
29687               return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
29688             }
29689
29690             for (var i = 0; i < way.nodes.length; i++) {
29691               curr = graph.entity(way.nodes[i]);
29692
29693               if (prev && curr && geoVecEqual(prev.loc, curr.loc, epsilon)) {
29694                 if (!isInteresting(prev, graph)) {
29695                   way = way.removeNode(prev.id);
29696                   graph = graph.replace(way).remove(prev);
29697                 } else if (!isInteresting(curr, graph)) {
29698                   way = way.removeNode(curr.id);
29699                   graph = graph.replace(way).remove(curr);
29700                 }
29701               }
29702
29703               prev = curr;
29704             }
29705
29706             return graph;
29707           } // Reorder nodes around intersections that have moved..
29708           //
29709           //  Start:                way1.nodes: b,e         (moving)
29710           //  a - b - c ----- d     way2.nodes: a,b,c,d     (static)
29711           //      |                 vertex: b
29712           //      e                 isEP1: true,  isEP2, false
29713           //
29714           //  way1 `b,e` moved here:
29715           //  a ----- c = b - d
29716           //              |
29717           //              e
29718           //
29719           //  reorder nodes         way1.nodes: b,e
29720           //  a ----- c - b - d     way2.nodes: a,c,b,d
29721           //              |
29722           //              e
29723           //
29724
29725
29726           function unZorroIntersection(intersection, graph) {
29727             var vertex = graph.entity(intersection.nodeId);
29728             var way1 = graph.entity(intersection.movedId);
29729             var way2 = graph.entity(intersection.unmovedId);
29730             var isEP1 = intersection.movedIsEP;
29731             var isEP2 = intersection.unmovedIsEP; // don't move the vertex if it is the endpoint of both ways.
29732
29733             if (isEP1 && isEP2) return graph;
29734             var nodes1 = graph.childNodes(way1).filter(function (n) {
29735               return n !== vertex;
29736             });
29737             var nodes2 = graph.childNodes(way2).filter(function (n) {
29738               return n !== vertex;
29739             });
29740             if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
29741             if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
29742             var edge1 = !isEP1 && geoChooseEdge(nodes1, projection(vertex.loc), projection);
29743             var edge2 = !isEP2 && geoChooseEdge(nodes2, projection(vertex.loc), projection);
29744             var loc; // snap vertex to nearest edge (or some point between them)..
29745
29746             if (!isEP1 && !isEP2) {
29747               var epsilon = 1e-6,
29748                   maxIter = 10;
29749
29750               for (var i = 0; i < maxIter; i++) {
29751                 loc = geoVecInterp(edge1.loc, edge2.loc, 0.5);
29752                 edge1 = geoChooseEdge(nodes1, projection(loc), projection);
29753                 edge2 = geoChooseEdge(nodes2, projection(loc), projection);
29754                 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
29755               }
29756             } else if (!isEP1) {
29757               loc = edge1.loc;
29758             } else {
29759               loc = edge2.loc;
29760             }
29761
29762             graph = graph.replace(vertex.move(loc)); // if zorro happened, reorder nodes..
29763
29764             if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
29765               way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
29766               graph = graph.replace(way1);
29767             }
29768
29769             if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
29770               way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
29771               graph = graph.replace(way2);
29772             }
29773
29774             return graph;
29775           }
29776
29777           function cleanupIntersections(graph) {
29778             for (var i = 0; i < cache.intersections.length; i++) {
29779               var obj = cache.intersections[i];
29780               graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, _delta);
29781               graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
29782               graph = unZorroIntersection(obj, graph);
29783               graph = removeDuplicateVertices(obj.movedId, graph);
29784               graph = removeDuplicateVertices(obj.unmovedId, graph);
29785             }
29786
29787             return graph;
29788           } // check if moving way endpoint can cross an unmoved way, if so limit delta..
29789
29790
29791           function limitDelta(graph) {
29792             function moveNode(loc) {
29793               return geoVecAdd(projection(loc), _delta);
29794             }
29795
29796             for (var i = 0; i < cache.intersections.length; i++) {
29797               var obj = cache.intersections[i]; // Don't limit movement if this is vertex joins 2 endpoints..
29798
29799               if (obj.movedIsEP && obj.unmovedIsEP) continue; // Don't limit movement if this vertex is not an endpoint anyway..
29800
29801               if (!obj.movedIsEP) continue;
29802               var node = graph.entity(obj.nodeId);
29803               var start = projection(node.loc);
29804               var end = geoVecAdd(start, _delta);
29805               var movedNodes = graph.childNodes(graph.entity(obj.movedId));
29806               var movedPath = movedNodes.map(function (n) {
29807                 return moveNode(n.loc);
29808               });
29809               var unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId));
29810               var unmovedPath = unmovedNodes.map(function (n) {
29811                 return projection(n.loc);
29812               });
29813               var hits = geoPathIntersections(movedPath, unmovedPath);
29814
29815               for (var j = 0; i < hits.length; i++) {
29816                 if (geoVecEqual(hits[j], end)) continue;
29817                 var edge = geoChooseEdge(unmovedNodes, end, projection);
29818                 _delta = geoVecSubtract(projection(edge.loc), start);
29819               }
29820             }
29821           }
29822
29823           var action = function action(graph) {
29824             if (_delta[0] === 0 && _delta[1] === 0) return graph;
29825             setupCache(graph);
29826
29827             if (cache.intersections.length) {
29828               limitDelta(graph);
29829             }
29830
29831             for (var i = 0; i < cache.nodes.length; i++) {
29832               var node = graph.entity(cache.nodes[i]);
29833               var start = projection(node.loc);
29834               var end = geoVecAdd(start, _delta);
29835               graph = graph.replace(node.move(projection.invert(end)));
29836             }
29837
29838             if (cache.intersections.length) {
29839               graph = cleanupIntersections(graph);
29840             }
29841
29842             return graph;
29843           };
29844
29845           action.delta = function () {
29846             return _delta;
29847           };
29848
29849           return action;
29850         }
29851
29852         function actionMoveMember(relationId, fromIndex, toIndex) {
29853           return function (graph) {
29854             return graph.replace(graph.entity(relationId).moveMember(fromIndex, toIndex));
29855           };
29856         }
29857
29858         function actionMoveNode(nodeID, toLoc) {
29859           var action = function action(graph, t) {
29860             if (t === null || !isFinite(t)) t = 1;
29861             t = Math.min(Math.max(+t, 0), 1);
29862             var node = graph.entity(nodeID);
29863             return graph.replace(node.move(geoVecInterp(node.loc, toLoc, t)));
29864           };
29865
29866           action.transitionable = true;
29867           return action;
29868         }
29869
29870         function actionNoop() {
29871           return function (graph) {
29872             return graph;
29873           };
29874         }
29875
29876         function actionOrthogonalize(wayID, projection, vertexID, degThresh, ep) {
29877           var epsilon = ep || 1e-4;
29878           var threshold = degThresh || 13; // degrees within right or straight to alter
29879           // We test normalized dot products so we can compare as cos(angle)
29880
29881           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
29882           var upperThreshold = Math.cos(threshold * Math.PI / 180);
29883
29884           var action = function action(graph, t) {
29885             if (t === null || !isFinite(t)) t = 1;
29886             t = Math.min(Math.max(+t, 0), 1);
29887             var way = graph.entity(wayID);
29888             way = way.removeNode(''); // sanity check - remove any consecutive duplicates
29889
29890             if (way.tags.nonsquare) {
29891               var tags = Object.assign({}, way.tags); // since we're squaring, remove indication that this is physically unsquare
29892
29893               delete tags.nonsquare;
29894               way = way.update({
29895                 tags: tags
29896               });
29897             }
29898
29899             graph = graph.replace(way);
29900             var isClosed = way.isClosed();
29901             var nodes = graph.childNodes(way).slice(); // shallow copy
29902
29903             if (isClosed) nodes.pop();
29904
29905             if (vertexID !== undefined) {
29906               nodes = nodeSubset(nodes, vertexID, isClosed);
29907               if (nodes.length !== 3) return graph;
29908             } // note: all geometry functions here use the unclosed node/point/coord list
29909
29910
29911             var nodeCount = {};
29912             var points = [];
29913             var corner = {
29914               i: 0,
29915               dotp: 1
29916             };
29917             var node, point, loc, score, motions, i, j;
29918
29919             for (i = 0; i < nodes.length; i++) {
29920               node = nodes[i];
29921               nodeCount[node.id] = (nodeCount[node.id] || 0) + 1;
29922               points.push({
29923                 id: node.id,
29924                 coord: projection(node.loc)
29925               });
29926             }
29927
29928             if (points.length === 3) {
29929               // move only one vertex for right triangle
29930               for (i = 0; i < 1000; i++) {
29931                 motions = points.map(calcMotion);
29932                 points[corner.i].coord = geoVecAdd(points[corner.i].coord, motions[corner.i]);
29933                 score = corner.dotp;
29934
29935                 if (score < epsilon) {
29936                   break;
29937                 }
29938               }
29939
29940               node = graph.entity(nodes[corner.i].id);
29941               loc = projection.invert(points[corner.i].coord);
29942               graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
29943             } else {
29944               var straights = [];
29945               var simplified = []; // Remove points from nearly straight sections..
29946               // This produces a simplified shape to orthogonalize
29947
29948               for (i = 0; i < points.length; i++) {
29949                 point = points[i];
29950                 var dotp = 0;
29951
29952                 if (isClosed || i > 0 && i < points.length - 1) {
29953                   var a = points[(i - 1 + points.length) % points.length];
29954                   var b = points[(i + 1) % points.length];
29955                   dotp = Math.abs(geoOrthoNormalizedDotProduct(a.coord, b.coord, point.coord));
29956                 }
29957
29958                 if (dotp > upperThreshold) {
29959                   straights.push(point);
29960                 } else {
29961                   simplified.push(point);
29962                 }
29963               } // Orthogonalize the simplified shape
29964
29965
29966               var bestPoints = clonePoints(simplified);
29967               var originalPoints = clonePoints(simplified);
29968               score = Infinity;
29969
29970               for (i = 0; i < 1000; i++) {
29971                 motions = simplified.map(calcMotion);
29972
29973                 for (j = 0; j < motions.length; j++) {
29974                   simplified[j].coord = geoVecAdd(simplified[j].coord, motions[j]);
29975                 }
29976
29977                 var newScore = geoOrthoCalcScore(simplified, isClosed, epsilon, threshold);
29978
29979                 if (newScore < score) {
29980                   bestPoints = clonePoints(simplified);
29981                   score = newScore;
29982                 }
29983
29984                 if (score < epsilon) {
29985                   break;
29986                 }
29987               }
29988
29989               var bestCoords = bestPoints.map(function (p) {
29990                 return p.coord;
29991               });
29992               if (isClosed) bestCoords.push(bestCoords[0]); // move the nodes that should move
29993
29994               for (i = 0; i < bestPoints.length; i++) {
29995                 point = bestPoints[i];
29996
29997                 if (!geoVecEqual(originalPoints[i].coord, point.coord)) {
29998                   node = graph.entity(point.id);
29999                   loc = projection.invert(point.coord);
30000                   graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
30001                 }
30002               } // move the nodes along straight segments
30003
30004
30005               for (i = 0; i < straights.length; i++) {
30006                 point = straights[i];
30007                 if (nodeCount[point.id] > 1) continue; // skip self-intersections
30008
30009                 node = graph.entity(point.id);
30010
30011                 if (t === 1 && graph.parentWays(node).length === 1 && graph.parentRelations(node).length === 0 && !node.hasInterestingTags()) {
30012                   // remove uninteresting points..
30013                   graph = actionDeleteNode(node.id)(graph);
30014                 } else {
30015                   // move interesting points to the nearest edge..
30016                   var choice = geoVecProject(point.coord, bestCoords);
30017
30018                   if (choice) {
30019                     loc = projection.invert(choice.target);
30020                     graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
30021                   }
30022                 }
30023               }
30024             }
30025
30026             return graph;
30027
30028             function clonePoints(array) {
30029               return array.map(function (p) {
30030                 return {
30031                   id: p.id,
30032                   coord: [p.coord[0], p.coord[1]]
30033                 };
30034               });
30035             }
30036
30037             function calcMotion(point, i, array) {
30038               // don't try to move the endpoints of a non-closed way.
30039               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)
30040
30041               if (nodeCount[array[i].id] > 1) return [0, 0];
30042               var a = array[(i - 1 + array.length) % array.length].coord;
30043               var origin = point.coord;
30044               var b = array[(i + 1) % array.length].coord;
30045               var p = geoVecSubtract(a, origin);
30046               var q = geoVecSubtract(b, origin);
30047               var scale = 2 * Math.min(geoVecLength(p), geoVecLength(q));
30048               p = geoVecNormalize(p);
30049               q = geoVecNormalize(q);
30050               var dotp = p[0] * q[0] + p[1] * q[1];
30051               var val = Math.abs(dotp);
30052
30053               if (val < lowerThreshold) {
30054                 // nearly orthogonal
30055                 corner.i = i;
30056                 corner.dotp = val;
30057                 var vec = geoVecNormalize(geoVecAdd(p, q));
30058                 return geoVecScale(vec, 0.1 * dotp * scale);
30059               }
30060
30061               return [0, 0]; // do nothing
30062             }
30063           }; // if we are only orthogonalizing one vertex,
30064           // get that vertex and the previous and next
30065
30066
30067           function nodeSubset(nodes, vertexID, isClosed) {
30068             var first = isClosed ? 0 : 1;
30069             var last = isClosed ? nodes.length : nodes.length - 1;
30070
30071             for (var i = first; i < last; i++) {
30072               if (nodes[i].id === vertexID) {
30073                 return [nodes[(i - 1 + nodes.length) % nodes.length], nodes[i], nodes[(i + 1) % nodes.length]];
30074               }
30075             }
30076
30077             return [];
30078           }
30079
30080           action.disabled = function (graph) {
30081             var way = graph.entity(wayID);
30082             way = way.removeNode(''); // sanity check - remove any consecutive duplicates
30083
30084             graph = graph.replace(way);
30085             var isClosed = way.isClosed();
30086             var nodes = graph.childNodes(way).slice(); // shallow copy
30087
30088             if (isClosed) nodes.pop();
30089             var allowStraightAngles = false;
30090
30091             if (vertexID !== undefined) {
30092               allowStraightAngles = true;
30093               nodes = nodeSubset(nodes, vertexID, isClosed);
30094               if (nodes.length !== 3) return 'end_vertex';
30095             }
30096
30097             var coords = nodes.map(function (n) {
30098               return projection(n.loc);
30099             });
30100             var score = geoOrthoCanOrthogonalize(coords, isClosed, epsilon, threshold, allowStraightAngles);
30101
30102             if (score === null) {
30103               return 'not_squarish';
30104             } else if (score === 0) {
30105               return 'square_enough';
30106             } else {
30107               return false;
30108             }
30109           };
30110
30111           action.transitionable = true;
30112           return action;
30113         }
30114
30115         //
30116         // `turn` must be an `osmTurn` object
30117         // see osm/intersection.js, pathToTurn()
30118         //
30119         // This specifies a restriction of type `restriction` when traveling from
30120         // `turn.from.way` toward `turn.to.way` via `turn.via.node` OR `turn.via.ways`.
30121         // (The action does not check that these entities form a valid intersection.)
30122         //
30123         // From, to, and via ways should be split before calling this action.
30124         // (old versions of the code would split the ways here, but we no longer do it)
30125         //
30126         // For testing convenience, accepts a restrictionID to assign to the new
30127         // relation. Normally, this will be undefined and the relation will
30128         // automatically be assigned a new ID.
30129         //
30130
30131         function actionRestrictTurn(turn, restrictionType, restrictionID) {
30132           return function (graph) {
30133             var fromWay = graph.entity(turn.from.way);
30134             var toWay = graph.entity(turn.to.way);
30135             var viaNode = turn.via.node && graph.entity(turn.via.node);
30136             var viaWays = turn.via.ways && turn.via.ways.map(function (id) {
30137               return graph.entity(id);
30138             });
30139             var members = [];
30140             members.push({
30141               id: fromWay.id,
30142               type: 'way',
30143               role: 'from'
30144             });
30145
30146             if (viaNode) {
30147               members.push({
30148                 id: viaNode.id,
30149                 type: 'node',
30150                 role: 'via'
30151               });
30152             } else if (viaWays) {
30153               viaWays.forEach(function (viaWay) {
30154                 members.push({
30155                   id: viaWay.id,
30156                   type: 'way',
30157                   role: 'via'
30158                 });
30159               });
30160             }
30161
30162             members.push({
30163               id: toWay.id,
30164               type: 'way',
30165               role: 'to'
30166             });
30167             return graph.replace(osmRelation({
30168               id: restrictionID,
30169               tags: {
30170                 type: 'restriction',
30171                 restriction: restrictionType
30172               },
30173               members: members
30174             }));
30175           };
30176         }
30177
30178         function actionRevert(id) {
30179           var action = function action(graph) {
30180             var entity = graph.hasEntity(id),
30181                 base = graph.base().entities[id];
30182
30183             if (entity && !base) {
30184               // entity will be removed..
30185               if (entity.type === 'node') {
30186                 graph.parentWays(entity).forEach(function (parent) {
30187                   parent = parent.removeNode(id);
30188                   graph = graph.replace(parent);
30189
30190                   if (parent.isDegenerate()) {
30191                     graph = actionDeleteWay(parent.id)(graph);
30192                   }
30193                 });
30194               }
30195
30196               graph.parentRelations(entity).forEach(function (parent) {
30197                 parent = parent.removeMembersWithID(id);
30198                 graph = graph.replace(parent);
30199
30200                 if (parent.isDegenerate()) {
30201                   graph = actionDeleteRelation(parent.id)(graph);
30202                 }
30203               });
30204             }
30205
30206             return graph.revert(id);
30207           };
30208
30209           return action;
30210         }
30211
30212         function actionRotate(rotateIds, pivot, angle, projection) {
30213           var action = function action(graph) {
30214             return graph.update(function (graph) {
30215               utilGetAllNodes(rotateIds, graph).forEach(function (node) {
30216                 var point = geoRotate([projection(node.loc)], angle, pivot)[0];
30217                 graph = graph.replace(node.move(projection.invert(point)));
30218               });
30219             });
30220           };
30221
30222           return action;
30223         }
30224
30225         function actionScale(ids, pivotLoc, scaleFactor, projection) {
30226           return function (graph) {
30227             return graph.update(function (graph) {
30228               var point, radial;
30229               utilGetAllNodes(ids, graph).forEach(function (node) {
30230                 point = projection(node.loc);
30231                 radial = [point[0] - pivotLoc[0], point[1] - pivotLoc[1]];
30232                 point = [pivotLoc[0] + scaleFactor * radial[0], pivotLoc[1] + scaleFactor * radial[1]];
30233                 graph = graph.replace(node.move(projection.invert(point)));
30234               });
30235             });
30236           };
30237         }
30238
30239         /* Align nodes along their common axis */
30240
30241         function actionStraightenNodes(nodeIDs, projection) {
30242           function positionAlongWay(a, o, b) {
30243             return geoVecDot(a, b, o) / geoVecDot(b, b, o);
30244           } // returns the endpoints of the long axis of symmetry of the `points` bounding rect
30245
30246
30247           function getEndpoints(points) {
30248             var ssr = geoGetSmallestSurroundingRectangle(points); // Choose line pq = axis of symmetry.
30249             // The shape's surrounding rectangle has 2 axes of symmetry.
30250             // Snap points to the long axis
30251
30252             var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
30253             var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
30254             var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
30255             var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
30256             var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
30257
30258             if (isLong) {
30259               return [p1, q1];
30260             }
30261
30262             return [p2, q2];
30263           }
30264
30265           var action = function action(graph, t) {
30266             if (t === null || !isFinite(t)) t = 1;
30267             t = Math.min(Math.max(+t, 0), 1);
30268             var nodes = nodeIDs.map(function (id) {
30269               return graph.entity(id);
30270             });
30271             var points = nodes.map(function (n) {
30272               return projection(n.loc);
30273             });
30274             var endpoints = getEndpoints(points);
30275             var startPoint = endpoints[0];
30276             var endPoint = endpoints[1]; // Move points onto the line connecting the endpoints
30277
30278             for (var i = 0; i < points.length; i++) {
30279               var node = nodes[i];
30280               var point = points[i];
30281               var u = positionAlongWay(point, startPoint, endPoint);
30282               var point2 = geoVecInterp(startPoint, endPoint, u);
30283               var loc2 = projection.invert(point2);
30284               graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
30285             }
30286
30287             return graph;
30288           };
30289
30290           action.disabled = function (graph) {
30291             var nodes = nodeIDs.map(function (id) {
30292               return graph.entity(id);
30293             });
30294             var points = nodes.map(function (n) {
30295               return projection(n.loc);
30296             });
30297             var endpoints = getEndpoints(points);
30298             var startPoint = endpoints[0];
30299             var endPoint = endpoints[1];
30300             var maxDistance = 0;
30301
30302             for (var i = 0; i < points.length; i++) {
30303               var point = points[i];
30304               var u = positionAlongWay(point, startPoint, endPoint);
30305               var p = geoVecInterp(startPoint, endPoint, u);
30306               var dist = geoVecLength(p, point);
30307
30308               if (!isNaN(dist) && dist > maxDistance) {
30309                 maxDistance = dist;
30310               }
30311             }
30312
30313             if (maxDistance < 0.0001) {
30314               return 'straight_enough';
30315             }
30316           };
30317
30318           action.transitionable = true;
30319           return action;
30320         }
30321
30322         /*
30323          * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
30324          */
30325
30326         function actionStraightenWay(selectedIDs, projection) {
30327           function positionAlongWay(a, o, b) {
30328             return geoVecDot(a, b, o) / geoVecDot(b, b, o);
30329           } // Return all selected ways as a continuous, ordered array of nodes
30330
30331
30332           function allNodes(graph) {
30333             var nodes = [];
30334             var startNodes = [];
30335             var endNodes = [];
30336             var remainingWays = [];
30337             var selectedWays = selectedIDs.filter(function (w) {
30338               return graph.entity(w).type === 'way';
30339             });
30340             var selectedNodes = selectedIDs.filter(function (n) {
30341               return graph.entity(n).type === 'node';
30342             });
30343
30344             for (var i = 0; i < selectedWays.length; i++) {
30345               var way = graph.entity(selectedWays[i]);
30346               nodes = way.nodes.slice(0);
30347               remainingWays.push(nodes);
30348               startNodes.push(nodes[0]);
30349               endNodes.push(nodes[nodes.length - 1]);
30350             } // Remove duplicate end/startNodes (duplicate nodes cannot be at the line end,
30351             //   and need to be removed so currNode difference calculation below works)
30352             // i.e. ["n-1", "n-1", "n-2"] => ["n-2"]
30353
30354
30355             startNodes = startNodes.filter(function (n) {
30356               return startNodes.indexOf(n) === startNodes.lastIndexOf(n);
30357             });
30358             endNodes = endNodes.filter(function (n) {
30359               return endNodes.indexOf(n) === endNodes.lastIndexOf(n);
30360             }); // Choose the initial endpoint to start from
30361
30362             var currNode = utilArrayDifference(startNodes, endNodes).concat(utilArrayDifference(endNodes, startNodes))[0];
30363             var nextWay = [];
30364             nodes = []; // Create nested function outside of loop to avoid "function in loop" lint error
30365
30366             var getNextWay = function getNextWay(currNode, remainingWays) {
30367               return remainingWays.filter(function (way) {
30368                 return way[0] === currNode || way[way.length - 1] === currNode;
30369               })[0];
30370             }; // Add nodes to end of nodes array, until all ways are added
30371
30372
30373             while (remainingWays.length) {
30374               nextWay = getNextWay(currNode, remainingWays);
30375               remainingWays = utilArrayDifference(remainingWays, [nextWay]);
30376
30377               if (nextWay[0] !== currNode) {
30378                 nextWay.reverse();
30379               }
30380
30381               nodes = nodes.concat(nextWay);
30382               currNode = nodes[nodes.length - 1];
30383             } // If user selected 2 nodes to straighten between, then slice nodes array to those nodes
30384
30385
30386             if (selectedNodes.length === 2) {
30387               var startNodeIdx = nodes.indexOf(selectedNodes[0]);
30388               var endNodeIdx = nodes.indexOf(selectedNodes[1]);
30389               var sortedStartEnd = [startNodeIdx, endNodeIdx];
30390               sortedStartEnd.sort(function (a, b) {
30391                 return a - b;
30392               });
30393               nodes = nodes.slice(sortedStartEnd[0], sortedStartEnd[1] + 1);
30394             }
30395
30396             return nodes.map(function (n) {
30397               return graph.entity(n);
30398             });
30399           }
30400
30401           function shouldKeepNode(node, graph) {
30402             return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
30403           }
30404
30405           var action = function action(graph, t) {
30406             if (t === null || !isFinite(t)) t = 1;
30407             t = Math.min(Math.max(+t, 0), 1);
30408             var nodes = allNodes(graph);
30409             var points = nodes.map(function (n) {
30410               return projection(n.loc);
30411             });
30412             var startPoint = points[0];
30413             var endPoint = points[points.length - 1];
30414             var toDelete = [];
30415             var i;
30416
30417             for (i = 1; i < points.length - 1; i++) {
30418               var node = nodes[i];
30419               var point = points[i];
30420
30421               if (t < 1 || shouldKeepNode(node, graph)) {
30422                 var u = positionAlongWay(point, startPoint, endPoint);
30423                 var p = geoVecInterp(startPoint, endPoint, u);
30424                 var loc2 = projection.invert(p);
30425                 graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
30426               } else {
30427                 // safe to delete
30428                 if (toDelete.indexOf(node) === -1) {
30429                   toDelete.push(node);
30430                 }
30431               }
30432             }
30433
30434             for (i = 0; i < toDelete.length; i++) {
30435               graph = actionDeleteNode(toDelete[i].id)(graph);
30436             }
30437
30438             return graph;
30439           };
30440
30441           action.disabled = function (graph) {
30442             // check way isn't too bendy
30443             var nodes = allNodes(graph);
30444             var points = nodes.map(function (n) {
30445               return projection(n.loc);
30446             });
30447             var startPoint = points[0];
30448             var endPoint = points[points.length - 1];
30449             var threshold = 0.2 * geoVecLength(startPoint, endPoint);
30450             var i;
30451
30452             if (threshold === 0) {
30453               return 'too_bendy';
30454             }
30455
30456             var maxDistance = 0;
30457
30458             for (i = 1; i < points.length - 1; i++) {
30459               var point = points[i];
30460               var u = positionAlongWay(point, startPoint, endPoint);
30461               var p = geoVecInterp(startPoint, endPoint, u);
30462               var dist = geoVecLength(p, point); // to bendy if point is off by 20% of total start/end distance in projected space
30463
30464               if (isNaN(dist) || dist > threshold) {
30465                 return 'too_bendy';
30466               } else if (dist > maxDistance) {
30467                 maxDistance = dist;
30468               }
30469             }
30470
30471             var keepingAllNodes = nodes.every(function (node, i) {
30472               return i === 0 || i === nodes.length - 1 || shouldKeepNode(node, graph);
30473             });
30474
30475             if (maxDistance < 0.0001 && // Allow straightening even if already straight in order to remove extraneous nodes
30476             keepingAllNodes) {
30477               return 'straight_enough';
30478             }
30479           };
30480
30481           action.transitionable = true;
30482           return action;
30483         }
30484
30485         //
30486         // `turn` must be an `osmTurn` object with a `restrictionID` property.
30487         // see osm/intersection.js, pathToTurn()
30488         //
30489
30490         function actionUnrestrictTurn(turn) {
30491           return function (graph) {
30492             return actionDeleteRelation(turn.restrictionID)(graph);
30493           };
30494         }
30495
30496         /* Reflect the given area around its axis of symmetry */
30497
30498         function actionReflect(reflectIds, projection) {
30499           var _useLongAxis = true;
30500
30501           var action = function action(graph, t) {
30502             if (t === null || !isFinite(t)) t = 1;
30503             t = Math.min(Math.max(+t, 0), 1);
30504             var nodes = utilGetAllNodes(reflectIds, graph);
30505             var points = nodes.map(function (n) {
30506               return projection(n.loc);
30507             });
30508             var ssr = geoGetSmallestSurroundingRectangle(points); // Choose line pq = axis of symmetry.
30509             // The shape's surrounding rectangle has 2 axes of symmetry.
30510             // Reflect across the longer axis by default.
30511
30512             var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
30513             var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
30514             var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
30515             var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
30516             var p, q;
30517             var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
30518
30519             if (_useLongAxis && isLong || !_useLongAxis && !isLong) {
30520               p = p1;
30521               q = q1;
30522             } else {
30523               p = p2;
30524               q = q2;
30525             } // reflect c across pq
30526             // http://math.stackexchange.com/questions/65503/point-reflection-over-a-line
30527
30528
30529             var dx = q[0] - p[0];
30530             var dy = q[1] - p[1];
30531             var a = (dx * dx - dy * dy) / (dx * dx + dy * dy);
30532             var b = 2 * dx * dy / (dx * dx + dy * dy);
30533
30534             for (var i = 0; i < nodes.length; i++) {
30535               var node = nodes[i];
30536               var c = projection(node.loc);
30537               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]];
30538               var loc2 = projection.invert(c2);
30539               node = node.move(geoVecInterp(node.loc, loc2, t));
30540               graph = graph.replace(node);
30541             }
30542
30543             return graph;
30544           };
30545
30546           action.useLongAxis = function (val) {
30547             if (!arguments.length) return _useLongAxis;
30548             _useLongAxis = val;
30549             return action;
30550           };
30551
30552           action.transitionable = true;
30553           return action;
30554         }
30555
30556         function actionUpgradeTags(entityId, oldTags, replaceTags) {
30557           return function (graph) {
30558             var entity = graph.entity(entityId);
30559             var tags = Object.assign({}, entity.tags); // shallow copy
30560
30561             var transferValue;
30562             var semiIndex;
30563
30564             for (var oldTagKey in oldTags) {
30565               if (!(oldTagKey in tags)) continue; // wildcard match
30566
30567               if (oldTags[oldTagKey] === '*') {
30568                 // note the value since we might need to transfer it
30569                 transferValue = tags[oldTagKey];
30570                 delete tags[oldTagKey]; // exact match
30571               } else if (oldTags[oldTagKey] === tags[oldTagKey]) {
30572                 delete tags[oldTagKey]; // match is within semicolon-delimited values
30573               } else {
30574                 var vals = tags[oldTagKey].split(';').filter(Boolean);
30575                 var oldIndex = vals.indexOf(oldTags[oldTagKey]);
30576
30577                 if (vals.length === 1 || oldIndex === -1) {
30578                   delete tags[oldTagKey];
30579                 } else {
30580                   if (replaceTags && replaceTags[oldTagKey]) {
30581                     // replacing a value within a semicolon-delimited value, note the index
30582                     semiIndex = oldIndex;
30583                   }
30584
30585                   vals.splice(oldIndex, 1);
30586                   tags[oldTagKey] = vals.join(';');
30587                 }
30588               }
30589             }
30590
30591             if (replaceTags) {
30592               for (var replaceKey in replaceTags) {
30593                 var replaceValue = replaceTags[replaceKey];
30594
30595                 if (replaceValue === '*') {
30596                   if (tags[replaceKey] && tags[replaceKey] !== 'no') {
30597                     // allow any pre-existing value except `no` (troll tag)
30598                     continue;
30599                   } else {
30600                     // otherwise assume `yes` is okay
30601                     tags[replaceKey] = 'yes';
30602                   }
30603                 } else if (replaceValue === '$1') {
30604                   tags[replaceKey] = transferValue;
30605                 } else {
30606                   if (tags[replaceKey] && oldTags[replaceKey] && semiIndex !== undefined) {
30607                     // don't override preexisting values
30608                     var existingVals = tags[replaceKey].split(';').filter(Boolean);
30609
30610                     if (existingVals.indexOf(replaceValue) === -1) {
30611                       existingVals.splice(semiIndex, 0, replaceValue);
30612                       tags[replaceKey] = existingVals.join(';');
30613                     }
30614                   } else {
30615                     tags[replaceKey] = replaceValue;
30616                   }
30617                 }
30618               }
30619             }
30620
30621             return graph.replace(entity.update({
30622               tags: tags
30623             }));
30624           };
30625         }
30626
30627         function behaviorEdit(context) {
30628           function behavior() {
30629             context.map().minzoom(context.minEditableZoom());
30630           }
30631
30632           behavior.off = function () {
30633             context.map().minzoom(0);
30634           };
30635
30636           return behavior;
30637         }
30638
30639         /*
30640            The hover behavior adds the `.hover` class on pointerover to all elements to which
30641            the identical datum is bound, and removes it on pointerout.
30642
30643            The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
30644            representation may consist of several elements scattered throughout the DOM hierarchy.
30645            Only one of these elements can have the :hover pseudo-class, but all of them will
30646            have the .hover class.
30647          */
30648
30649         function behaviorHover(context) {
30650           var dispatch$1 = dispatch('hover');
30651
30652           var _selection = select(null);
30653
30654           var _newNodeId = null;
30655           var _initialNodeID = null;
30656
30657           var _altDisables;
30658
30659           var _ignoreVertex;
30660
30661           var _targets = []; // use pointer events on supported platforms; fallback to mouse events
30662
30663           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
30664
30665           function keydown(d3_event) {
30666             if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
30667               _selection.selectAll('.hover').classed('hover-suppressed', true).classed('hover', false);
30668
30669               _selection.classed('hover-disabled', true);
30670
30671               dispatch$1.call('hover', this, null);
30672             }
30673           }
30674
30675           function keyup(d3_event) {
30676             if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
30677               _selection.selectAll('.hover-suppressed').classed('hover-suppressed', false).classed('hover', true);
30678
30679               _selection.classed('hover-disabled', false);
30680
30681               dispatch$1.call('hover', this, _targets);
30682             }
30683           }
30684
30685           function behavior(selection) {
30686             _selection = selection;
30687             _targets = [];
30688
30689             if (_initialNodeID) {
30690               _newNodeId = _initialNodeID;
30691               _initialNodeID = null;
30692             } else {
30693               _newNodeId = null;
30694             }
30695
30696             _selection.on(_pointerPrefix + 'over.hover', pointerover).on(_pointerPrefix + 'out.hover', pointerout) // treat pointerdown as pointerover for touch devices
30697             .on(_pointerPrefix + 'down.hover', pointerover);
30698
30699             select(window).on(_pointerPrefix + 'up.hover pointercancel.hover', pointerout, true).on('keydown.hover', keydown).on('keyup.hover', keyup);
30700
30701             function eventTarget(d3_event) {
30702               var datum = d3_event.target && d3_event.target.__data__;
30703               if (_typeof(datum) !== 'object') return null;
30704
30705               if (!(datum instanceof osmEntity) && datum.properties && datum.properties.entity instanceof osmEntity) {
30706                 return datum.properties.entity;
30707               }
30708
30709               return datum;
30710             }
30711
30712             function pointerover(d3_event) {
30713               // ignore mouse hovers with buttons pressed unless dragging
30714               if (context.mode().id.indexOf('drag') === -1 && (!d3_event.pointerType || d3_event.pointerType === 'mouse') && d3_event.buttons) return;
30715               var target = eventTarget(d3_event);
30716
30717               if (target && _targets.indexOf(target) === -1) {
30718                 _targets.push(target);
30719
30720                 updateHover(d3_event, _targets);
30721               }
30722             }
30723
30724             function pointerout(d3_event) {
30725               var target = eventTarget(d3_event);
30726
30727               var index = _targets.indexOf(target);
30728
30729               if (index !== -1) {
30730                 _targets.splice(index);
30731
30732                 updateHover(d3_event, _targets);
30733               }
30734             }
30735
30736             function allowsVertex(d) {
30737               return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
30738             }
30739
30740             function modeAllowsHover(target) {
30741               var mode = context.mode();
30742
30743               if (mode.id === 'add-point') {
30744                 return mode.preset.matchGeometry('vertex') || target.type !== 'way' && target.geometry(context.graph()) !== 'vertex';
30745               }
30746
30747               return true;
30748             }
30749
30750             function updateHover(d3_event, targets) {
30751               _selection.selectAll('.hover').classed('hover', false);
30752
30753               _selection.selectAll('.hover-suppressed').classed('hover-suppressed', false);
30754
30755               var mode = context.mode();
30756
30757               if (!_newNodeId && (mode.id === 'draw-line' || mode.id === 'draw-area')) {
30758                 var node = targets.find(function (target) {
30759                   return target instanceof osmEntity && target.type === 'node';
30760                 });
30761                 _newNodeId = node && node.id;
30762               }
30763
30764               targets = targets.filter(function (datum) {
30765                 if (datum instanceof osmEntity) {
30766                   // If drawing a way, don't hover on a node that was just placed. #3974
30767                   return datum.id !== _newNodeId && (datum.type !== 'node' || !_ignoreVertex || allowsVertex(datum)) && modeAllowsHover(datum);
30768                 }
30769
30770                 return true;
30771               });
30772               var selector = '';
30773
30774               for (var i in targets) {
30775                 var datum = targets[i]; // What are we hovering over?
30776
30777                 if (datum.__featurehash__) {
30778                   // hovering custom data
30779                   selector += ', .data' + datum.__featurehash__;
30780                 } else if (datum instanceof QAItem) {
30781                   selector += ', .' + datum.service + '.itemId-' + datum.id;
30782                 } else if (datum instanceof osmNote) {
30783                   selector += ', .note-' + datum.id;
30784                 } else if (datum instanceof osmEntity) {
30785                   selector += ', .' + datum.id;
30786
30787                   if (datum.type === 'relation') {
30788                     for (var j in datum.members) {
30789                       selector += ', .' + datum.members[j].id;
30790                     }
30791                   }
30792                 }
30793               }
30794
30795               var suppressed = _altDisables && d3_event && d3_event.altKey;
30796
30797               if (selector.trim().length) {
30798                 // remove the first comma
30799                 selector = selector.slice(1);
30800
30801                 _selection.selectAll(selector).classed(suppressed ? 'hover-suppressed' : 'hover', true);
30802               }
30803
30804               dispatch$1.call('hover', this, !suppressed && targets);
30805             }
30806           }
30807
30808           behavior.off = function (selection) {
30809             selection.selectAll('.hover').classed('hover', false);
30810             selection.selectAll('.hover-suppressed').classed('hover-suppressed', false);
30811             selection.classed('hover-disabled', false);
30812             selection.on(_pointerPrefix + 'over.hover', null).on(_pointerPrefix + 'out.hover', null).on(_pointerPrefix + 'down.hover', null);
30813             select(window).on(_pointerPrefix + 'up.hover pointercancel.hover', null, true).on('keydown.hover', null).on('keyup.hover', null);
30814           };
30815
30816           behavior.altDisables = function (val) {
30817             if (!arguments.length) return _altDisables;
30818             _altDisables = val;
30819             return behavior;
30820           };
30821
30822           behavior.ignoreVertex = function (val) {
30823             if (!arguments.length) return _ignoreVertex;
30824             _ignoreVertex = val;
30825             return behavior;
30826           };
30827
30828           behavior.initialNodeID = function (nodeId) {
30829             _initialNodeID = nodeId;
30830             return behavior;
30831           };
30832
30833           return utilRebind(behavior, dispatch$1, 'on');
30834         }
30835
30836         var _disableSpace = false;
30837         var _lastSpace = null;
30838         function behaviorDraw(context) {
30839           var dispatch$1 = dispatch('move', 'down', 'downcancel', 'click', 'clickWay', 'clickNode', 'undo', 'cancel', 'finish');
30840           var keybinding = utilKeybinding('draw');
30841
30842           var _hover = behaviorHover(context).altDisables(true).ignoreVertex(true).on('hover', context.ui().sidebar.hover);
30843
30844           var _edit = behaviorEdit(context);
30845
30846           var _closeTolerance = 4;
30847           var _tolerance = 12;
30848           var _mouseLeave = false;
30849           var _lastMouse = null;
30850
30851           var _lastPointerUpEvent;
30852
30853           var _downPointer; // use pointer events on supported platforms; fallback to mouse events
30854
30855
30856           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // related code
30857           // - `mode/drag_node.js` `datum()`
30858
30859
30860           function datum(d3_event) {
30861             var mode = context.mode();
30862             var isNote = mode && mode.id.indexOf('note') !== -1;
30863             if (d3_event.altKey || isNote) return {};
30864             var element;
30865
30866             if (d3_event.type === 'keydown') {
30867               element = _lastMouse && _lastMouse.target;
30868             } else {
30869               element = d3_event.target;
30870             } // When drawing, snap only to touch targets..
30871             // (this excludes area fills and active drawing elements)
30872
30873
30874             var d = element.__data__;
30875             return d && d.properties && d.properties.target ? d : {};
30876           }
30877
30878           function pointerdown(d3_event) {
30879             if (_downPointer) return;
30880             var pointerLocGetter = utilFastMouse(this);
30881             _downPointer = {
30882               id: d3_event.pointerId || 'mouse',
30883               pointerLocGetter: pointerLocGetter,
30884               downTime: +new Date(),
30885               downLoc: pointerLocGetter(d3_event)
30886             };
30887             dispatch$1.call('down', this, d3_event, datum(d3_event));
30888           }
30889
30890           function pointerup(d3_event) {
30891             if (!_downPointer || _downPointer.id !== (d3_event.pointerId || 'mouse')) return;
30892             var downPointer = _downPointer;
30893             _downPointer = null;
30894             _lastPointerUpEvent = d3_event;
30895             if (downPointer.isCancelled) return;
30896             var t2 = +new Date();
30897             var p2 = downPointer.pointerLocGetter(d3_event);
30898             var dist = geoVecLength(downPointer.downLoc, p2);
30899
30900             if (dist < _closeTolerance || dist < _tolerance && t2 - downPointer.downTime < 500) {
30901               // Prevent a quick second click
30902               select(window).on('click.draw-block', function () {
30903                 d3_event.stopPropagation();
30904               }, true);
30905               context.map().dblclickZoomEnable(false);
30906               window.setTimeout(function () {
30907                 context.map().dblclickZoomEnable(true);
30908                 select(window).on('click.draw-block', null);
30909               }, 500);
30910               click(d3_event, p2);
30911             }
30912           }
30913
30914           function pointermove(d3_event) {
30915             if (_downPointer && _downPointer.id === (d3_event.pointerId || 'mouse') && !_downPointer.isCancelled) {
30916               var p2 = _downPointer.pointerLocGetter(d3_event);
30917
30918               var dist = geoVecLength(_downPointer.downLoc, p2);
30919
30920               if (dist >= _closeTolerance) {
30921                 _downPointer.isCancelled = true;
30922                 dispatch$1.call('downcancel', this);
30923               }
30924             }
30925
30926             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
30927             // events immediately after non-mouse pointerup events; detect and ignore them.
30928
30929             if (_lastPointerUpEvent && _lastPointerUpEvent.pointerType !== 'mouse' && d3_event.timeStamp - _lastPointerUpEvent.timeStamp < 100) return;
30930             _lastMouse = d3_event;
30931             dispatch$1.call('move', this, d3_event, datum(d3_event));
30932           }
30933
30934           function pointercancel(d3_event) {
30935             if (_downPointer && _downPointer.id === (d3_event.pointerId || 'mouse')) {
30936               if (!_downPointer.isCancelled) {
30937                 dispatch$1.call('downcancel', this);
30938               }
30939
30940               _downPointer = null;
30941             }
30942           }
30943
30944           function mouseenter() {
30945             _mouseLeave = false;
30946           }
30947
30948           function mouseleave() {
30949             _mouseLeave = true;
30950           }
30951
30952           function allowsVertex(d) {
30953             return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
30954           } // related code
30955           // - `mode/drag_node.js`     `doMove()`
30956           // - `behavior/draw.js`      `click()`
30957           // - `behavior/draw_way.js`  `move()`
30958
30959
30960           function click(d3_event, loc) {
30961             var d = datum(d3_event);
30962             var target = d && d.properties && d.properties.entity;
30963             var mode = context.mode();
30964
30965             if (target && target.type === 'node' && allowsVertex(target)) {
30966               // Snap to a node
30967               dispatch$1.call('clickNode', this, target, d);
30968               return;
30969             } else if (target && target.type === 'way' && (mode.id !== 'add-point' || mode.preset.matchGeometry('vertex'))) {
30970               // Snap to a way
30971               var choice = geoChooseEdge(context.graph().childNodes(target), loc, context.projection, context.activeID());
30972
30973               if (choice) {
30974                 var edge = [target.nodes[choice.index - 1], target.nodes[choice.index]];
30975                 dispatch$1.call('clickWay', this, choice.loc, edge, d);
30976                 return;
30977               }
30978             } else if (mode.id !== 'add-point' || mode.preset.matchGeometry('point')) {
30979               var locLatLng = context.projection.invert(loc);
30980               dispatch$1.call('click', this, locLatLng, d);
30981             }
30982           } // treat a spacebar press like a click
30983
30984
30985           function space(d3_event) {
30986             d3_event.preventDefault();
30987             d3_event.stopPropagation();
30988             var currSpace = context.map().mouse();
30989
30990             if (_disableSpace && _lastSpace) {
30991               var dist = geoVecLength(_lastSpace, currSpace);
30992
30993               if (dist > _tolerance) {
30994                 _disableSpace = false;
30995               }
30996             }
30997
30998             if (_disableSpace || _mouseLeave || !_lastMouse) return; // user must move mouse or release space bar to allow another click
30999
31000             _lastSpace = currSpace;
31001             _disableSpace = true;
31002             select(window).on('keyup.space-block', function () {
31003               d3_event.preventDefault();
31004               d3_event.stopPropagation();
31005               _disableSpace = false;
31006               select(window).on('keyup.space-block', null);
31007             }); // get the current mouse position
31008
31009             var loc = context.map().mouse() || // or the map center if the mouse has never entered the map
31010             context.projection(context.map().center());
31011             click(d3_event, loc);
31012           }
31013
31014           function backspace(d3_event) {
31015             d3_event.preventDefault();
31016             dispatch$1.call('undo');
31017           }
31018
31019           function del(d3_event) {
31020             d3_event.preventDefault();
31021             dispatch$1.call('cancel');
31022           }
31023
31024           function ret(d3_event) {
31025             d3_event.preventDefault();
31026             dispatch$1.call('finish');
31027           }
31028
31029           function behavior(selection) {
31030             context.install(_hover);
31031             context.install(_edit);
31032             _downPointer = null;
31033             keybinding.on('⌫', backspace).on('⌦', del).on('⎋', ret).on('↩', ret).on('space', space).on('⌥space', space);
31034             selection.on('mouseenter.draw', mouseenter).on('mouseleave.draw', mouseleave).on(_pointerPrefix + 'down.draw', pointerdown).on(_pointerPrefix + 'move.draw', pointermove);
31035             select(window).on(_pointerPrefix + 'up.draw', pointerup, true).on('pointercancel.draw', pointercancel, true);
31036             select(document).call(keybinding);
31037             return behavior;
31038           }
31039
31040           behavior.off = function (selection) {
31041             context.ui().sidebar.hover.cancel();
31042             context.uninstall(_hover);
31043             context.uninstall(_edit);
31044             selection.on('mouseenter.draw', null).on('mouseleave.draw', null).on(_pointerPrefix + 'down.draw', null).on(_pointerPrefix + 'move.draw', null);
31045             select(window).on(_pointerPrefix + 'up.draw', null).on('pointercancel.draw', null); // note: keyup.space-block, click.draw-block should remain
31046
31047             select(document).call(keybinding.unbind);
31048           };
31049
31050           behavior.hover = function () {
31051             return _hover;
31052           };
31053
31054           return utilRebind(behavior, dispatch$1, 'on');
31055         }
31056
31057         function initRange(domain, range) {
31058           switch (arguments.length) {
31059             case 0:
31060               break;
31061
31062             case 1:
31063               this.range(domain);
31064               break;
31065
31066             default:
31067               this.range(range).domain(domain);
31068               break;
31069           }
31070
31071           return this;
31072         }
31073
31074         function constants(x) {
31075           return function () {
31076             return x;
31077           };
31078         }
31079
31080         function number$1(x) {
31081           return +x;
31082         }
31083
31084         var unit = [0, 1];
31085         function identity$3(x) {
31086           return x;
31087         }
31088
31089         function normalize$1(a, b) {
31090           return (b -= a = +a) ? function (x) {
31091             return (x - a) / b;
31092           } : constants(isNaN(b) ? NaN : 0.5);
31093         }
31094
31095         function clamper(a, b) {
31096           var t;
31097           if (a > b) t = a, a = b, b = t;
31098           return function (x) {
31099             return Math.max(a, Math.min(b, x));
31100           };
31101         } // normalize(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
31102         // interpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding range value x in [a,b].
31103
31104
31105         function bimap(domain, range, interpolate) {
31106           var d0 = domain[0],
31107               d1 = domain[1],
31108               r0 = range[0],
31109               r1 = range[1];
31110           if (d1 < d0) d0 = normalize$1(d1, d0), r0 = interpolate(r1, r0);else d0 = normalize$1(d0, d1), r0 = interpolate(r0, r1);
31111           return function (x) {
31112             return r0(d0(x));
31113           };
31114         }
31115
31116         function polymap(domain, range, interpolate) {
31117           var j = Math.min(domain.length, range.length) - 1,
31118               d = new Array(j),
31119               r = new Array(j),
31120               i = -1; // Reverse descending domains.
31121
31122           if (domain[j] < domain[0]) {
31123             domain = domain.slice().reverse();
31124             range = range.slice().reverse();
31125           }
31126
31127           while (++i < j) {
31128             d[i] = normalize$1(domain[i], domain[i + 1]);
31129             r[i] = interpolate(range[i], range[i + 1]);
31130           }
31131
31132           return function (x) {
31133             var i = bisectRight(domain, x, 1, j) - 1;
31134             return r[i](d[i](x));
31135           };
31136         }
31137
31138         function copy(source, target) {
31139           return target.domain(source.domain()).range(source.range()).interpolate(source.interpolate()).clamp(source.clamp()).unknown(source.unknown());
31140         }
31141         function transformer$1() {
31142           var domain = unit,
31143               range = unit,
31144               interpolate$1 = interpolate,
31145               transform,
31146               untransform,
31147               unknown,
31148               clamp = identity$3,
31149               piecewise,
31150               output,
31151               input;
31152
31153           function rescale() {
31154             var n = Math.min(domain.length, range.length);
31155             if (clamp !== identity$3) clamp = clamper(domain[0], domain[n - 1]);
31156             piecewise = n > 2 ? polymap : bimap;
31157             output = input = null;
31158             return scale;
31159           }
31160
31161           function scale(x) {
31162             return isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate$1)))(transform(clamp(x)));
31163           }
31164
31165           scale.invert = function (y) {
31166             return clamp(untransform((input || (input = piecewise(range, domain.map(transform), d3_interpolateNumber)))(y)));
31167           };
31168
31169           scale.domain = function (_) {
31170             return arguments.length ? (domain = Array.from(_, number$1), rescale()) : domain.slice();
31171           };
31172
31173           scale.range = function (_) {
31174             return arguments.length ? (range = Array.from(_), rescale()) : range.slice();
31175           };
31176
31177           scale.rangeRound = function (_) {
31178             return range = Array.from(_), interpolate$1 = interpolateRound, rescale();
31179           };
31180
31181           scale.clamp = function (_) {
31182             return arguments.length ? (clamp = _ ? true : identity$3, rescale()) : clamp !== identity$3;
31183           };
31184
31185           scale.interpolate = function (_) {
31186             return arguments.length ? (interpolate$1 = _, rescale()) : interpolate$1;
31187           };
31188
31189           scale.unknown = function (_) {
31190             return arguments.length ? (unknown = _, scale) : unknown;
31191           };
31192
31193           return function (t, u) {
31194             transform = t, untransform = u;
31195             return rescale();
31196           };
31197         }
31198         function continuous() {
31199           return transformer$1()(identity$3, identity$3);
31200         }
31201
31202         function formatDecimal (x) {
31203           return Math.abs(x = Math.round(x)) >= 1e21 ? x.toLocaleString("en").replace(/,/g, "") : x.toString(10);
31204         } // Computes the decimal coefficient and exponent of the specified number x with
31205         // significant digits p, where x is positive and p is in [1, 21] or undefined.
31206         // For example, formatDecimalParts(1.23) returns ["123", 0].
31207
31208         function formatDecimalParts(x, p) {
31209           if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
31210
31211           var i,
31212               coefficient = x.slice(0, i); // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
31213           // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
31214
31215           return [coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient, +x.slice(i + 1)];
31216         }
31217
31218         function exponent (x) {
31219           return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;
31220         }
31221
31222         function formatGroup (grouping, thousands) {
31223           return function (value, width) {
31224             var i = value.length,
31225                 t = [],
31226                 j = 0,
31227                 g = grouping[0],
31228                 length = 0;
31229
31230             while (i > 0 && g > 0) {
31231               if (length + g + 1 > width) g = Math.max(1, width - length);
31232               t.push(value.substring(i -= g, i + g));
31233               if ((length += g + 1) > width) break;
31234               g = grouping[j = (j + 1) % grouping.length];
31235             }
31236
31237             return t.reverse().join(thousands);
31238           };
31239         }
31240
31241         function formatNumerals (numerals) {
31242           return function (value) {
31243             return value.replace(/[0-9]/g, function (i) {
31244               return numerals[+i];
31245             });
31246           };
31247         }
31248
31249         // [[fill]align][sign][symbol][0][width][,][.precision][~][type]
31250         var re = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;
31251         function formatSpecifier(specifier) {
31252           if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
31253           var match;
31254           return new FormatSpecifier({
31255             fill: match[1],
31256             align: match[2],
31257             sign: match[3],
31258             symbol: match[4],
31259             zero: match[5],
31260             width: match[6],
31261             comma: match[7],
31262             precision: match[8] && match[8].slice(1),
31263             trim: match[9],
31264             type: match[10]
31265           });
31266         }
31267         formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
31268
31269         function FormatSpecifier(specifier) {
31270           this.fill = specifier.fill === undefined ? " " : specifier.fill + "";
31271           this.align = specifier.align === undefined ? ">" : specifier.align + "";
31272           this.sign = specifier.sign === undefined ? "-" : specifier.sign + "";
31273           this.symbol = specifier.symbol === undefined ? "" : specifier.symbol + "";
31274           this.zero = !!specifier.zero;
31275           this.width = specifier.width === undefined ? undefined : +specifier.width;
31276           this.comma = !!specifier.comma;
31277           this.precision = specifier.precision === undefined ? undefined : +specifier.precision;
31278           this.trim = !!specifier.trim;
31279           this.type = specifier.type === undefined ? "" : specifier.type + "";
31280         }
31281
31282         FormatSpecifier.prototype.toString = function () {
31283           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;
31284         };
31285
31286         // Trims insignificant zeros, e.g., replaces 1.2000k with 1.2k.
31287         function formatTrim (s) {
31288           out: for (var n = s.length, i = 1, i0 = -1, i1; i < n; ++i) {
31289             switch (s[i]) {
31290               case ".":
31291                 i0 = i1 = i;
31292                 break;
31293
31294               case "0":
31295                 if (i0 === 0) i0 = i;
31296                 i1 = i;
31297                 break;
31298
31299               default:
31300                 if (!+s[i]) break out;
31301                 if (i0 > 0) i0 = 0;
31302                 break;
31303             }
31304           }
31305
31306           return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;
31307         }
31308
31309         // `thisNumberValue` abstract operation
31310         // https://tc39.github.io/ecma262/#sec-thisnumbervalue
31311         var thisNumberValue = function (value) {
31312           if (typeof value != 'number' && classofRaw(value) != 'Number') {
31313             throw TypeError('Incorrect invocation');
31314           }
31315           return +value;
31316         };
31317
31318         // `String.prototype.repeat` method implementation
31319         // https://tc39.github.io/ecma262/#sec-string.prototype.repeat
31320         var stringRepeat = ''.repeat || function repeat(count) {
31321           var str = String(requireObjectCoercible(this));
31322           var result = '';
31323           var n = toInteger(count);
31324           if (n < 0 || n == Infinity) throw RangeError('Wrong number of repetitions');
31325           for (;n > 0; (n >>>= 1) && (str += str)) if (n & 1) result += str;
31326           return result;
31327         };
31328
31329         var nativeToFixed = 1.0.toFixed;
31330         var floor$6 = Math.floor;
31331
31332         var pow$2 = function (x, n, acc) {
31333           return n === 0 ? acc : n % 2 === 1 ? pow$2(x, n - 1, acc * x) : pow$2(x * x, n / 2, acc);
31334         };
31335
31336         var log$2 = function (x) {
31337           var n = 0;
31338           var x2 = x;
31339           while (x2 >= 4096) {
31340             n += 12;
31341             x2 /= 4096;
31342           }
31343           while (x2 >= 2) {
31344             n += 1;
31345             x2 /= 2;
31346           } return n;
31347         };
31348
31349         var FORCED$c = nativeToFixed && (
31350           0.00008.toFixed(3) !== '0.000' ||
31351           0.9.toFixed(0) !== '1' ||
31352           1.255.toFixed(2) !== '1.25' ||
31353           1000000000000000128.0.toFixed(0) !== '1000000000000000128'
31354         ) || !fails(function () {
31355           // V8 ~ Android 4.3-
31356           nativeToFixed.call({});
31357         });
31358
31359         // `Number.prototype.toFixed` method
31360         // https://tc39.github.io/ecma262/#sec-number.prototype.tofixed
31361         _export({ target: 'Number', proto: true, forced: FORCED$c }, {
31362           // eslint-disable-next-line max-statements
31363           toFixed: function toFixed(fractionDigits) {
31364             var number = thisNumberValue(this);
31365             var fractDigits = toInteger(fractionDigits);
31366             var data = [0, 0, 0, 0, 0, 0];
31367             var sign = '';
31368             var result = '0';
31369             var e, z, j, k;
31370
31371             var multiply = function (n, c) {
31372               var index = -1;
31373               var c2 = c;
31374               while (++index < 6) {
31375                 c2 += n * data[index];
31376                 data[index] = c2 % 1e7;
31377                 c2 = floor$6(c2 / 1e7);
31378               }
31379             };
31380
31381             var divide = function (n) {
31382               var index = 6;
31383               var c = 0;
31384               while (--index >= 0) {
31385                 c += data[index];
31386                 data[index] = floor$6(c / n);
31387                 c = (c % n) * 1e7;
31388               }
31389             };
31390
31391             var dataToString = function () {
31392               var index = 6;
31393               var s = '';
31394               while (--index >= 0) {
31395                 if (s !== '' || index === 0 || data[index] !== 0) {
31396                   var t = String(data[index]);
31397                   s = s === '' ? t : s + stringRepeat.call('0', 7 - t.length) + t;
31398                 }
31399               } return s;
31400             };
31401
31402             if (fractDigits < 0 || fractDigits > 20) throw RangeError('Incorrect fraction digits');
31403             // eslint-disable-next-line no-self-compare
31404             if (number != number) return 'NaN';
31405             if (number <= -1e21 || number >= 1e21) return String(number);
31406             if (number < 0) {
31407               sign = '-';
31408               number = -number;
31409             }
31410             if (number > 1e-21) {
31411               e = log$2(number * pow$2(2, 69, 1)) - 69;
31412               z = e < 0 ? number * pow$2(2, -e, 1) : number / pow$2(2, e, 1);
31413               z *= 0x10000000000000;
31414               e = 52 - e;
31415               if (e > 0) {
31416                 multiply(0, z);
31417                 j = fractDigits;
31418                 while (j >= 7) {
31419                   multiply(1e7, 0);
31420                   j -= 7;
31421                 }
31422                 multiply(pow$2(10, j, 1), 0);
31423                 j = e - 1;
31424                 while (j >= 23) {
31425                   divide(1 << 23);
31426                   j -= 23;
31427                 }
31428                 divide(1 << j);
31429                 multiply(1, 1);
31430                 divide(2);
31431                 result = dataToString();
31432               } else {
31433                 multiply(0, z);
31434                 multiply(1 << -e, 0);
31435                 result = dataToString() + stringRepeat.call('0', fractDigits);
31436               }
31437             }
31438             if (fractDigits > 0) {
31439               k = result.length;
31440               result = sign + (k <= fractDigits
31441                 ? '0.' + stringRepeat.call('0', fractDigits - k) + result
31442                 : result.slice(0, k - fractDigits) + '.' + result.slice(k - fractDigits));
31443             } else {
31444               result = sign + result;
31445             } return result;
31446           }
31447         });
31448
31449         var nativeToPrecision = 1.0.toPrecision;
31450
31451         var FORCED$d = fails(function () {
31452           // IE7-
31453           return nativeToPrecision.call(1, undefined) !== '1';
31454         }) || !fails(function () {
31455           // V8 ~ Android 4.3-
31456           nativeToPrecision.call({});
31457         });
31458
31459         // `Number.prototype.toPrecision` method
31460         // https://tc39.github.io/ecma262/#sec-number.prototype.toprecision
31461         _export({ target: 'Number', proto: true, forced: FORCED$d }, {
31462           toPrecision: function toPrecision(precision) {
31463             return precision === undefined
31464               ? nativeToPrecision.call(thisNumberValue(this))
31465               : nativeToPrecision.call(thisNumberValue(this), precision);
31466           }
31467         });
31468
31469         var prefixExponent;
31470         function formatPrefixAuto (x, p) {
31471           var d = formatDecimalParts(x, p);
31472           if (!d) return x + "";
31473           var coefficient = d[0],
31474               exponent = d[1],
31475               i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
31476               n = coefficient.length;
31477           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!
31478         }
31479
31480         function formatRounded (x, p) {
31481           var d = formatDecimalParts(x, p);
31482           if (!d) return x + "";
31483           var coefficient = d[0],
31484               exponent = d[1];
31485           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");
31486         }
31487
31488         var formatTypes = {
31489           "%": function _(x, p) {
31490             return (x * 100).toFixed(p);
31491           },
31492           "b": function b(x) {
31493             return Math.round(x).toString(2);
31494           },
31495           "c": function c(x) {
31496             return x + "";
31497           },
31498           "d": formatDecimal,
31499           "e": function e(x, p) {
31500             return x.toExponential(p);
31501           },
31502           "f": function f(x, p) {
31503             return x.toFixed(p);
31504           },
31505           "g": function g(x, p) {
31506             return x.toPrecision(p);
31507           },
31508           "o": function o(x) {
31509             return Math.round(x).toString(8);
31510           },
31511           "p": function p(x, _p) {
31512             return formatRounded(x * 100, _p);
31513           },
31514           "r": formatRounded,
31515           "s": formatPrefixAuto,
31516           "X": function X(x) {
31517             return Math.round(x).toString(16).toUpperCase();
31518           },
31519           "x": function x(_x) {
31520             return Math.round(_x).toString(16);
31521           }
31522         };
31523
31524         function identity$4 (x) {
31525           return x;
31526         }
31527
31528         var map = Array.prototype.map,
31529             prefixes = ["y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y"];
31530         function formatLocale (locale) {
31531           var group = locale.grouping === undefined || locale.thousands === undefined ? identity$4 : formatGroup(map.call(locale.grouping, Number), locale.thousands + ""),
31532               currencyPrefix = locale.currency === undefined ? "" : locale.currency[0] + "",
31533               currencySuffix = locale.currency === undefined ? "" : locale.currency[1] + "",
31534               decimal = locale.decimal === undefined ? "." : locale.decimal + "",
31535               numerals = locale.numerals === undefined ? identity$4 : formatNumerals(map.call(locale.numerals, String)),
31536               percent = locale.percent === undefined ? "%" : locale.percent + "",
31537               minus = locale.minus === undefined ? "−" : locale.minus + "",
31538               nan = locale.nan === undefined ? "NaN" : locale.nan + "";
31539
31540           function newFormat(specifier) {
31541             specifier = formatSpecifier(specifier);
31542             var fill = specifier.fill,
31543                 align = specifier.align,
31544                 sign = specifier.sign,
31545                 symbol = specifier.symbol,
31546                 zero = specifier.zero,
31547                 width = specifier.width,
31548                 comma = specifier.comma,
31549                 precision = specifier.precision,
31550                 trim = specifier.trim,
31551                 type = specifier.type; // The "n" type is an alias for ",g".
31552
31553             if (type === "n") comma = true, type = "g"; // The "" type, and any invalid type, is an alias for ".12~g".
31554             else if (!formatTypes[type]) precision === undefined && (precision = 12), trim = true, type = "g"; // If zero fill is specified, padding goes after sign and before digits.
31555
31556             if (zero || fill === "0" && align === "=") zero = true, fill = "0", align = "="; // Compute the prefix and suffix.
31557             // For SI-prefix, the suffix is lazily computed.
31558
31559             var prefix = symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
31560                 suffix = symbol === "$" ? currencySuffix : /[%p]/.test(type) ? percent : ""; // What format function should we use?
31561             // Is this an integer type?
31562             // Can this type generate exponential notation?
31563
31564             var formatType = formatTypes[type],
31565                 maybeSuffix = /[defgprs%]/.test(type); // Set the default precision if not specified,
31566             // or clamp the specified precision to the supported range.
31567             // For significant precision, it must be in [1, 21].
31568             // For fixed precision, it must be in [0, 20].
31569
31570             precision = precision === undefined ? 6 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision)) : Math.max(0, Math.min(20, precision));
31571
31572             function format(value) {
31573               var valuePrefix = prefix,
31574                   valueSuffix = suffix,
31575                   i,
31576                   n,
31577                   c;
31578
31579               if (type === "c") {
31580                 valueSuffix = formatType(value) + valueSuffix;
31581                 value = "";
31582               } else {
31583                 value = +value; // Determine the sign. -0 is not less than 0, but 1 / -0 is!
31584
31585                 var valueNegative = value < 0 || 1 / value < 0; // Perform the initial formatting.
31586
31587                 value = isNaN(value) ? nan : formatType(Math.abs(value), precision); // Trim insignificant zeros.
31588
31589                 if (trim) value = formatTrim(value); // If a negative value rounds to zero after formatting, and no explicit positive sign is requested, hide the sign.
31590
31591                 if (valueNegative && +value === 0 && sign !== "+") valueNegative = false; // Compute the prefix and suffix.
31592
31593                 valuePrefix = (valueNegative ? sign === "(" ? sign : minus : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
31594                 valueSuffix = (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign === "(" ? ")" : ""); // Break the formatted value into the integer “value” part that can be
31595                 // grouped, and fractional or exponential “suffix” part that is not.
31596
31597                 if (maybeSuffix) {
31598                   i = -1, n = value.length;
31599
31600                   while (++i < n) {
31601                     if (c = value.charCodeAt(i), 48 > c || c > 57) {
31602                       valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
31603                       value = value.slice(0, i);
31604                       break;
31605                     }
31606                   }
31607                 }
31608               } // If the fill character is not "0", grouping is applied before padding.
31609
31610
31611               if (comma && !zero) value = group(value, Infinity); // Compute the padding.
31612
31613               var length = valuePrefix.length + value.length + valueSuffix.length,
31614                   padding = length < width ? new Array(width - length + 1).join(fill) : ""; // If the fill character is "0", grouping is applied after padding.
31615
31616               if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = ""; // Reconstruct the final output based on the desired alignment.
31617
31618               switch (align) {
31619                 case "<":
31620                   value = valuePrefix + value + valueSuffix + padding;
31621                   break;
31622
31623                 case "=":
31624                   value = valuePrefix + padding + value + valueSuffix;
31625                   break;
31626
31627                 case "^":
31628                   value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
31629                   break;
31630
31631                 default:
31632                   value = padding + valuePrefix + value + valueSuffix;
31633                   break;
31634               }
31635
31636               return numerals(value);
31637             }
31638
31639             format.toString = function () {
31640               return specifier + "";
31641             };
31642
31643             return format;
31644           }
31645
31646           function formatPrefix(specifier, value) {
31647             var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
31648                 e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
31649                 k = Math.pow(10, -e),
31650                 prefix = prefixes[8 + e / 3];
31651             return function (value) {
31652               return f(k * value) + prefix;
31653             };
31654           }
31655
31656           return {
31657             format: newFormat,
31658             formatPrefix: formatPrefix
31659           };
31660         }
31661
31662         var locale;
31663         var format;
31664         var formatPrefix;
31665         defaultLocale({
31666           thousands: ",",
31667           grouping: [3],
31668           currency: ["$", ""]
31669         });
31670         function defaultLocale(definition) {
31671           locale = formatLocale(definition);
31672           format = locale.format;
31673           formatPrefix = locale.formatPrefix;
31674           return locale;
31675         }
31676
31677         function precisionFixed (step) {
31678           return Math.max(0, -exponent(Math.abs(step)));
31679         }
31680
31681         function precisionPrefix (step, value) {
31682           return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));
31683         }
31684
31685         function precisionRound (step, max) {
31686           step = Math.abs(step), max = Math.abs(max) - step;
31687           return Math.max(0, exponent(max) - exponent(step)) + 1;
31688         }
31689
31690         function tickFormat(start, stop, count, specifier) {
31691           var step = tickStep(start, stop, count),
31692               precision;
31693           specifier = formatSpecifier(specifier == null ? ",f" : specifier);
31694
31695           switch (specifier.type) {
31696             case "s":
31697               {
31698                 var value = Math.max(Math.abs(start), Math.abs(stop));
31699                 if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
31700                 return formatPrefix(specifier, value);
31701               }
31702
31703             case "":
31704             case "e":
31705             case "g":
31706             case "p":
31707             case "r":
31708               {
31709                 if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
31710                 break;
31711               }
31712
31713             case "f":
31714             case "%":
31715               {
31716                 if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
31717                 break;
31718               }
31719           }
31720
31721           return format(specifier);
31722         }
31723
31724         function linearish(scale) {
31725           var domain = scale.domain;
31726
31727           scale.ticks = function (count) {
31728             var d = domain();
31729             return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
31730           };
31731
31732           scale.tickFormat = function (count, specifier) {
31733             var d = domain();
31734             return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier);
31735           };
31736
31737           scale.nice = function (count) {
31738             if (count == null) count = 10;
31739             var d = domain();
31740             var i0 = 0;
31741             var i1 = d.length - 1;
31742             var start = d[i0];
31743             var stop = d[i1];
31744             var prestep;
31745             var step;
31746             var maxIter = 10;
31747
31748             if (stop < start) {
31749               step = start, start = stop, stop = step;
31750               step = i0, i0 = i1, i1 = step;
31751             }
31752
31753             while (maxIter-- > 0) {
31754               step = tickIncrement(start, stop, count);
31755
31756               if (step === prestep) {
31757                 d[i0] = start;
31758                 d[i1] = stop;
31759                 return domain(d);
31760               } else if (step > 0) {
31761                 start = Math.floor(start / step) * step;
31762                 stop = Math.ceil(stop / step) * step;
31763               } else if (step < 0) {
31764                 start = Math.ceil(start * step) / step;
31765                 stop = Math.floor(stop * step) / step;
31766               } else {
31767                 break;
31768               }
31769
31770               prestep = step;
31771             }
31772
31773             return scale;
31774           };
31775
31776           return scale;
31777         }
31778         function linear$2() {
31779           var scale = continuous();
31780
31781           scale.copy = function () {
31782             return copy(scale, linear$2());
31783           };
31784
31785           initRange.apply(scale, arguments);
31786           return linearish(scale);
31787         }
31788
31789         var nativeExpm1 = Math.expm1;
31790         var exp$1 = Math.exp;
31791
31792         // `Math.expm1` method implementation
31793         // https://tc39.github.io/ecma262/#sec-math.expm1
31794         var mathExpm1 = (!nativeExpm1
31795           // Old FF bug
31796           || nativeExpm1(10) > 22025.465794806719 || nativeExpm1(10) < 22025.4657948067165168
31797           // Tor Browser bug
31798           || nativeExpm1(-2e-17) != -2e-17
31799         ) ? function expm1(x) {
31800           return (x = +x) == 0 ? x : x > -1e-6 && x < 1e-6 ? x + x * x / 2 : exp$1(x) - 1;
31801         } : nativeExpm1;
31802
31803         function quantize() {
31804           var x0 = 0,
31805               x1 = 1,
31806               n = 1,
31807               domain = [0.5],
31808               range = [0, 1],
31809               unknown;
31810
31811           function scale(x) {
31812             return x <= x ? range[bisectRight(domain, x, 0, n)] : unknown;
31813           }
31814
31815           function rescale() {
31816             var i = -1;
31817             domain = new Array(n);
31818
31819             while (++i < n) {
31820               domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
31821             }
31822
31823             return scale;
31824           }
31825
31826           scale.domain = function (_) {
31827             var _ref, _ref2;
31828
31829             return arguments.length ? ((_ref = _, _ref2 = _slicedToArray(_ref, 2), x0 = _ref2[0], x1 = _ref2[1], _ref), x0 = +x0, x1 = +x1, rescale()) : [x0, x1];
31830           };
31831
31832           scale.range = function (_) {
31833             return arguments.length ? (n = (range = Array.from(_)).length - 1, rescale()) : range.slice();
31834           };
31835
31836           scale.invertExtent = function (y) {
31837             var i = range.indexOf(y);
31838             return i < 0 ? [NaN, NaN] : i < 1 ? [x0, domain[0]] : i >= n ? [domain[n - 1], x1] : [domain[i - 1], domain[i]];
31839           };
31840
31841           scale.unknown = function (_) {
31842             return arguments.length ? (unknown = _, scale) : scale;
31843           };
31844
31845           scale.thresholds = function () {
31846             return domain.slice();
31847           };
31848
31849           scale.copy = function () {
31850             return quantize().domain([x0, x1]).range(range).unknown(unknown);
31851           };
31852
31853           return initRange.apply(linearish(scale), arguments);
31854         }
31855
31856         // https://github.com/tc39/proposal-string-pad-start-end
31857
31858
31859
31860
31861         var ceil$1 = Math.ceil;
31862
31863         // `String.prototype.{ padStart, padEnd }` methods implementation
31864         var createMethod$6 = function (IS_END) {
31865           return function ($this, maxLength, fillString) {
31866             var S = String(requireObjectCoercible($this));
31867             var stringLength = S.length;
31868             var fillStr = fillString === undefined ? ' ' : String(fillString);
31869             var intMaxLength = toLength(maxLength);
31870             var fillLen, stringFiller;
31871             if (intMaxLength <= stringLength || fillStr == '') return S;
31872             fillLen = intMaxLength - stringLength;
31873             stringFiller = stringRepeat.call(fillStr, ceil$1(fillLen / fillStr.length));
31874             if (stringFiller.length > fillLen) stringFiller = stringFiller.slice(0, fillLen);
31875             return IS_END ? S + stringFiller : stringFiller + S;
31876           };
31877         };
31878
31879         var stringPad = {
31880           // `String.prototype.padStart` method
31881           // https://tc39.github.io/ecma262/#sec-string.prototype.padstart
31882           start: createMethod$6(false),
31883           // `String.prototype.padEnd` method
31884           // https://tc39.github.io/ecma262/#sec-string.prototype.padend
31885           end: createMethod$6(true)
31886         };
31887
31888         var padStart = stringPad.start;
31889
31890         var abs$3 = Math.abs;
31891         var DatePrototype$1 = Date.prototype;
31892         var getTime$1 = DatePrototype$1.getTime;
31893         var nativeDateToISOString = DatePrototype$1.toISOString;
31894
31895         // `Date.prototype.toISOString` method implementation
31896         // https://tc39.github.io/ecma262/#sec-date.prototype.toisostring
31897         // PhantomJS / old WebKit fails here:
31898         var dateToIsoString = (fails(function () {
31899           return nativeDateToISOString.call(new Date(-5e13 - 1)) != '0385-07-25T07:06:39.999Z';
31900         }) || !fails(function () {
31901           nativeDateToISOString.call(new Date(NaN));
31902         })) ? function toISOString() {
31903           if (!isFinite(getTime$1.call(this))) throw RangeError('Invalid time value');
31904           var date = this;
31905           var year = date.getUTCFullYear();
31906           var milliseconds = date.getUTCMilliseconds();
31907           var sign = year < 0 ? '-' : year > 9999 ? '+' : '';
31908           return sign + padStart(abs$3(year), sign ? 6 : 4, 0) +
31909             '-' + padStart(date.getUTCMonth() + 1, 2, 0) +
31910             '-' + padStart(date.getUTCDate(), 2, 0) +
31911             'T' + padStart(date.getUTCHours(), 2, 0) +
31912             ':' + padStart(date.getUTCMinutes(), 2, 0) +
31913             ':' + padStart(date.getUTCSeconds(), 2, 0) +
31914             '.' + padStart(milliseconds, 3, 0) +
31915             'Z';
31916         } : nativeDateToISOString;
31917
31918         // `Date.prototype.toISOString` method
31919         // https://tc39.github.io/ecma262/#sec-date.prototype.toisostring
31920         // PhantomJS / old WebKit has a broken implementations
31921         _export({ target: 'Date', proto: true, forced: Date.prototype.toISOString !== dateToIsoString }, {
31922           toISOString: dateToIsoString
31923         });
31924
31925         function behaviorBreathe() {
31926           var duration = 800;
31927           var steps = 4;
31928           var selector = '.selected.shadow, .selected .shadow';
31929
31930           var _selected = select(null);
31931
31932           var _classed = '';
31933           var _params = {};
31934           var _done = false;
31935
31936           var _timer;
31937
31938           function ratchetyInterpolator(a, b, steps, units) {
31939             a = parseFloat(a);
31940             b = parseFloat(b);
31941             var sample = quantize().domain([0, 1]).range(d3_quantize(d3_interpolateNumber(a, b), steps));
31942             return function (t) {
31943               return String(sample(t)) + (units || '');
31944             };
31945           }
31946
31947           function reset(selection) {
31948             selection.style('stroke-opacity', null).style('stroke-width', null).style('fill-opacity', null).style('r', null);
31949           }
31950
31951           function setAnimationParams(transition, fromTo) {
31952             var toFrom = fromTo === 'from' ? 'to' : 'from';
31953             transition.styleTween('stroke-opacity', function (d) {
31954               return ratchetyInterpolator(_params[d.id][toFrom].opacity, _params[d.id][fromTo].opacity, steps);
31955             }).styleTween('stroke-width', function (d) {
31956               return ratchetyInterpolator(_params[d.id][toFrom].width, _params[d.id][fromTo].width, steps, 'px');
31957             }).styleTween('fill-opacity', function (d) {
31958               return ratchetyInterpolator(_params[d.id][toFrom].opacity, _params[d.id][fromTo].opacity, steps);
31959             }).styleTween('r', function (d) {
31960               return ratchetyInterpolator(_params[d.id][toFrom].width, _params[d.id][fromTo].width, steps, 'px');
31961             });
31962           }
31963
31964           function calcAnimationParams(selection) {
31965             selection.call(reset).each(function (d) {
31966               var s = select(this);
31967               var tag = s.node().tagName;
31968               var p = {
31969                 'from': {},
31970                 'to': {}
31971               };
31972               var opacity;
31973               var width; // determine base opacity and width
31974
31975               if (tag === 'circle') {
31976                 opacity = parseFloat(s.style('fill-opacity') || 0.5);
31977                 width = parseFloat(s.style('r') || 15.5);
31978               } else {
31979                 opacity = parseFloat(s.style('stroke-opacity') || 0.7);
31980                 width = parseFloat(s.style('stroke-width') || 10);
31981               } // calculate from/to interpolation params..
31982
31983
31984               p.tag = tag;
31985               p.from.opacity = opacity * 0.6;
31986               p.to.opacity = opacity * 1.25;
31987               p.from.width = width * 0.7;
31988               p.to.width = width * (tag === 'circle' ? 1.5 : 1);
31989               _params[d.id] = p;
31990             });
31991           }
31992
31993           function run(surface, fromTo) {
31994             var toFrom = fromTo === 'from' ? 'to' : 'from';
31995             var currSelected = surface.selectAll(selector);
31996             var currClassed = surface.attr('class');
31997
31998             if (_done || currSelected.empty()) {
31999               _selected.call(reset);
32000
32001               _selected = select(null);
32002               return;
32003             }
32004
32005             if (!fastDeepEqual(currSelected.data(), _selected.data()) || currClassed !== _classed) {
32006               _selected.call(reset);
32007
32008               _classed = currClassed;
32009               _selected = currSelected.call(calcAnimationParams);
32010             }
32011
32012             var didCallNextRun = false;
32013
32014             _selected.transition().duration(duration).call(setAnimationParams, fromTo).on('end', function () {
32015               // `end` event is called for each selected element, but we want
32016               // it to run only once
32017               if (!didCallNextRun) {
32018                 surface.call(run, toFrom);
32019                 didCallNextRun = true;
32020               } // if entity was deselected, remove breathe styling
32021
32022
32023               if (!select(this).classed('selected')) {
32024                 reset(select(this));
32025               }
32026             });
32027           }
32028
32029           function behavior(surface) {
32030             _done = false;
32031             _timer = timer(function () {
32032               // wait for elements to actually become selected
32033               if (surface.selectAll(selector).empty()) {
32034                 return false;
32035               }
32036
32037               surface.call(run, 'from');
32038
32039               _timer.stop();
32040
32041               return true;
32042             }, 20);
32043           }
32044
32045           behavior.restartIfNeeded = function (surface) {
32046             if (_selected.empty()) {
32047               surface.call(run, 'from');
32048
32049               if (_timer) {
32050                 _timer.stop();
32051               }
32052             }
32053           };
32054
32055           behavior.off = function () {
32056             _done = true;
32057
32058             if (_timer) {
32059               _timer.stop();
32060             }
32061
32062             _selected.interrupt().call(reset);
32063           };
32064
32065           return behavior;
32066         }
32067
32068         /* Creates a keybinding behavior for an operation */
32069         function behaviorOperation(context) {
32070           var _operation;
32071
32072           function keypress(d3_event) {
32073             // prevent operations during low zoom selection
32074             if (!context.map().withinEditableZoom()) return;
32075             if (_operation.availableForKeypress && !_operation.availableForKeypress()) return;
32076             d3_event.preventDefault();
32077
32078             var disabled = _operation.disabled();
32079
32080             if (disabled) {
32081               context.ui().flash.duration(4000).iconName('#iD-operation-' + _operation.id).iconClass('operation disabled').label(_operation.tooltip)();
32082             } else {
32083               context.ui().flash.duration(2000).iconName('#iD-operation-' + _operation.id).iconClass('operation').label(_operation.annotation() || _operation.title)();
32084               if (_operation.point) _operation.point(null);
32085
32086               _operation();
32087             }
32088           }
32089
32090           function behavior() {
32091             if (_operation && _operation.available()) {
32092               context.keybinding().on(_operation.keys, keypress);
32093             }
32094
32095             return behavior;
32096           }
32097
32098           behavior.off = function () {
32099             context.keybinding().off(_operation.keys);
32100           };
32101
32102           behavior.which = function (_) {
32103             if (!arguments.length) return _operation;
32104             _operation = _;
32105             return behavior;
32106           };
32107
32108           return behavior;
32109         }
32110
32111         function operationCircularize(context, selectedIDs) {
32112           var _extent;
32113
32114           var _actions = selectedIDs.map(getAction).filter(Boolean);
32115
32116           var _amount = _actions.length === 1 ? 'single' : 'multiple';
32117
32118           var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function (n) {
32119             return n.loc;
32120           });
32121
32122           function getAction(entityID) {
32123             var entity = context.entity(entityID);
32124             if (entity.type !== 'way' || new Set(entity.nodes).size <= 1) return null;
32125
32126             if (!_extent) {
32127               _extent = entity.extent(context.graph());
32128             } else {
32129               _extent = _extent.extend(entity.extent(context.graph()));
32130             }
32131
32132             return actionCircularize(entityID, context.projection);
32133           }
32134
32135           var operation = function operation() {
32136             if (!_actions.length) return;
32137
32138             var combinedAction = function combinedAction(graph, t) {
32139               _actions.forEach(function (action) {
32140                 if (!action.disabled(graph)) {
32141                   graph = action(graph, t);
32142                 }
32143               });
32144
32145               return graph;
32146             };
32147
32148             combinedAction.transitionable = true;
32149             context.perform(combinedAction, operation.annotation());
32150             window.setTimeout(function () {
32151               context.validator().validate();
32152             }, 300); // after any transition
32153           };
32154
32155           operation.available = function () {
32156             return _actions.length && selectedIDs.length === _actions.length;
32157           }; // don't cache this because the visible extent could change
32158
32159
32160           operation.disabled = function () {
32161             if (!_actions.length) return '';
32162
32163             var actionDisableds = _actions.map(function (action) {
32164               return action.disabled(context.graph());
32165             }).filter(Boolean);
32166
32167             if (actionDisableds.length === _actions.length) {
32168               // none of the features can be circularized
32169               if (new Set(actionDisableds).size > 1) {
32170                 return 'multiple_blockers';
32171               }
32172
32173               return actionDisableds[0];
32174             } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
32175               return 'too_large';
32176             } else if (someMissing()) {
32177               return 'not_downloaded';
32178             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32179               return 'connected_to_hidden';
32180             }
32181
32182             return false;
32183
32184             function someMissing() {
32185               if (context.inIntro()) return false;
32186               var osm = context.connection();
32187
32188               if (osm) {
32189                 var missing = _coords.filter(function (loc) {
32190                   return !osm.isDataLoaded(loc);
32191                 });
32192
32193                 if (missing.length) {
32194                   missing.forEach(function (loc) {
32195                     context.loadTileAtLoc(loc);
32196                   });
32197                   return true;
32198                 }
32199               }
32200
32201               return false;
32202             }
32203           };
32204
32205           operation.tooltip = function () {
32206             var disable = operation.disabled();
32207             return disable ? _t('operations.circularize.' + disable + '.' + _amount) : _t('operations.circularize.description.' + _amount);
32208           };
32209
32210           operation.annotation = function () {
32211             return _t('operations.circularize.annotation.feature', {
32212               n: _actions.length
32213             });
32214           };
32215
32216           operation.id = 'circularize';
32217           operation.keys = [_t('operations.circularize.key')];
32218           operation.title = _t('operations.circularize.title');
32219           operation.behavior = behaviorOperation(context).which(operation);
32220           return operation;
32221         }
32222
32223         // For example, ⌘Z -> Ctrl+Z
32224
32225         var uiCmd = function uiCmd(code) {
32226           var detected = utilDetect();
32227
32228           if (detected.os === 'mac') {
32229             return code;
32230           }
32231
32232           if (detected.os === 'win') {
32233             if (code === '⌘⇧Z') return 'Ctrl+Y';
32234           }
32235
32236           var result = '',
32237               replacements = {
32238             '⌘': 'Ctrl',
32239             '⇧': 'Shift',
32240             '⌥': 'Alt',
32241             '⌫': 'Backspace',
32242             '⌦': 'Delete'
32243           };
32244
32245           for (var i = 0; i < code.length; i++) {
32246             if (code[i] in replacements) {
32247               result += replacements[code[i]] + (i < code.length - 1 ? '+' : '');
32248             } else {
32249               result += code[i];
32250             }
32251           }
32252
32253           return result;
32254         }; // return a display-focused string for a given keyboard code
32255
32256         uiCmd.display = function (code) {
32257           if (code.length !== 1) return code;
32258           var detected = utilDetect();
32259           var mac = detected.os === 'mac';
32260           var replacements = {
32261             '⌘': mac ? '⌘ ' + _t('shortcuts.key.cmd') : _t('shortcuts.key.ctrl'),
32262             '⇧': mac ? '⇧ ' + _t('shortcuts.key.shift') : _t('shortcuts.key.shift'),
32263             '⌥': mac ? '⌥ ' + _t('shortcuts.key.option') : _t('shortcuts.key.alt'),
32264             '⌃': mac ? '⌃ ' + _t('shortcuts.key.ctrl') : _t('shortcuts.key.ctrl'),
32265             '⌫': mac ? '⌫ ' + _t('shortcuts.key.delete') : _t('shortcuts.key.backspace'),
32266             '⌦': mac ? '⌦ ' + _t('shortcuts.key.del') : _t('shortcuts.key.del'),
32267             '↖': mac ? '↖ ' + _t('shortcuts.key.pgup') : _t('shortcuts.key.pgup'),
32268             '↘': mac ? '↘ ' + _t('shortcuts.key.pgdn') : _t('shortcuts.key.pgdn'),
32269             '⇞': mac ? '⇞ ' + _t('shortcuts.key.home') : _t('shortcuts.key.home'),
32270             '⇟': mac ? '⇟ ' + _t('shortcuts.key.end') : _t('shortcuts.key.end'),
32271             '↵': mac ? '⏎ ' + _t('shortcuts.key.return') : _t('shortcuts.key.enter'),
32272             '⎋': mac ? '⎋ ' + _t('shortcuts.key.esc') : _t('shortcuts.key.esc'),
32273             '☰': mac ? '☰ ' + _t('shortcuts.key.menu') : _t('shortcuts.key.menu')
32274           };
32275           return replacements[code] || code;
32276         };
32277
32278         function operationDelete(context, selectedIDs) {
32279           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32280           var action = actionDeleteMultiple(selectedIDs);
32281           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32282           var coords = nodes.map(function (n) {
32283             return n.loc;
32284           });
32285           var extent = utilTotalExtent(selectedIDs, context.graph());
32286
32287           var operation = function operation() {
32288             var nextSelectedID;
32289             var nextSelectedLoc;
32290
32291             if (selectedIDs.length === 1) {
32292               var id = selectedIDs[0];
32293               var entity = context.entity(id);
32294               var geometry = entity.geometry(context.graph());
32295               var parents = context.graph().parentWays(entity);
32296               var parent = parents[0]; // Select the next closest node in the way.
32297
32298               if (geometry === 'vertex') {
32299                 var nodes = parent.nodes;
32300                 var i = nodes.indexOf(id);
32301
32302                 if (i === 0) {
32303                   i++;
32304                 } else if (i === nodes.length - 1) {
32305                   i--;
32306                 } else {
32307                   var a = geoSphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc);
32308                   var b = geoSphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
32309                   i = a < b ? i - 1 : i + 1;
32310                 }
32311
32312                 nextSelectedID = nodes[i];
32313                 nextSelectedLoc = context.entity(nextSelectedID).loc;
32314               }
32315             }
32316
32317             context.perform(action, operation.annotation());
32318             context.validator().validate();
32319
32320             if (nextSelectedID && nextSelectedLoc) {
32321               if (context.hasEntity(nextSelectedID)) {
32322                 context.enter(modeSelect(context, [nextSelectedID]).follow(true));
32323               } else {
32324                 context.map().centerEase(nextSelectedLoc);
32325                 context.enter(modeBrowse(context));
32326               }
32327             } else {
32328               context.enter(modeBrowse(context));
32329             }
32330           };
32331
32332           operation.available = function () {
32333             return true;
32334           };
32335
32336           operation.disabled = function () {
32337             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32338               return 'too_large';
32339             } else if (someMissing()) {
32340               return 'not_downloaded';
32341             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32342               return 'connected_to_hidden';
32343             } else if (selectedIDs.some(protectedMember)) {
32344               return 'part_of_relation';
32345             } else if (selectedIDs.some(incompleteRelation)) {
32346               return 'incomplete_relation';
32347             } else if (selectedIDs.some(hasWikidataTag)) {
32348               return 'has_wikidata_tag';
32349             }
32350
32351             return false;
32352
32353             function someMissing() {
32354               if (context.inIntro()) return false;
32355               var osm = context.connection();
32356
32357               if (osm) {
32358                 var missing = coords.filter(function (loc) {
32359                   return !osm.isDataLoaded(loc);
32360                 });
32361
32362                 if (missing.length) {
32363                   missing.forEach(function (loc) {
32364                     context.loadTileAtLoc(loc);
32365                   });
32366                   return true;
32367                 }
32368               }
32369
32370               return false;
32371             }
32372
32373             function hasWikidataTag(id) {
32374               var entity = context.entity(id);
32375               return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
32376             }
32377
32378             function incompleteRelation(id) {
32379               var entity = context.entity(id);
32380               return entity.type === 'relation' && !entity.isComplete(context.graph());
32381             }
32382
32383             function protectedMember(id) {
32384               var entity = context.entity(id);
32385               if (entity.type !== 'way') return false;
32386               var parents = context.graph().parentRelations(entity);
32387
32388               for (var i = 0; i < parents.length; i++) {
32389                 var parent = parents[i];
32390                 var type = parent.tags.type;
32391                 var role = parent.memberById(id).role || 'outer';
32392
32393                 if (type === 'route' || type === 'boundary' || type === 'multipolygon' && role === 'outer') {
32394                   return true;
32395                 }
32396               }
32397
32398               return false;
32399             }
32400           };
32401
32402           operation.tooltip = function () {
32403             var disable = operation.disabled();
32404             return disable ? _t('operations.delete.' + disable + '.' + multi) : _t('operations.delete.description.' + multi);
32405           };
32406
32407           operation.annotation = function () {
32408             return selectedIDs.length === 1 ? _t('operations.delete.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.delete.annotation.feature', {
32409               n: selectedIDs.length
32410             });
32411           };
32412
32413           operation.id = 'delete';
32414           operation.keys = [uiCmd('⌘⌫'), uiCmd('⌘⌦'), uiCmd('⌦')];
32415           operation.title = _t('operations.delete.title');
32416           operation.behavior = behaviorOperation(context).which(operation);
32417           return operation;
32418         }
32419
32420         function operationOrthogonalize(context, selectedIDs) {
32421           var _extent;
32422
32423           var _type;
32424
32425           var _actions = selectedIDs.map(chooseAction).filter(Boolean);
32426
32427           var _amount = _actions.length === 1 ? 'single' : 'multiple';
32428
32429           var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function (n) {
32430             return n.loc;
32431           });
32432
32433           function chooseAction(entityID) {
32434             var entity = context.entity(entityID);
32435             var geometry = entity.geometry(context.graph());
32436
32437             if (!_extent) {
32438               _extent = entity.extent(context.graph());
32439             } else {
32440               _extent = _extent.extend(entity.extent(context.graph()));
32441             } // square a line/area
32442
32443
32444             if (entity.type === 'way' && new Set(entity.nodes).size > 2) {
32445               if (_type && _type !== 'feature') return null;
32446               _type = 'feature';
32447               return actionOrthogonalize(entityID, context.projection); // square a single vertex
32448             } else if (geometry === 'vertex') {
32449               if (_type && _type !== 'corner') return null;
32450               _type = 'corner';
32451               var graph = context.graph();
32452               var parents = graph.parentWays(entity);
32453
32454               if (parents.length === 1) {
32455                 var way = parents[0];
32456
32457                 if (way.nodes.indexOf(entityID) !== -1) {
32458                   return actionOrthogonalize(way.id, context.projection, entityID);
32459                 }
32460               }
32461             }
32462
32463             return null;
32464           }
32465
32466           var operation = function operation() {
32467             if (!_actions.length) return;
32468
32469             var combinedAction = function combinedAction(graph, t) {
32470               _actions.forEach(function (action) {
32471                 if (!action.disabled(graph)) {
32472                   graph = action(graph, t);
32473                 }
32474               });
32475
32476               return graph;
32477             };
32478
32479             combinedAction.transitionable = true;
32480             context.perform(combinedAction, operation.annotation());
32481             window.setTimeout(function () {
32482               context.validator().validate();
32483             }, 300); // after any transition
32484           };
32485
32486           operation.available = function () {
32487             return _actions.length && selectedIDs.length === _actions.length;
32488           }; // don't cache this because the visible extent could change
32489
32490
32491           operation.disabled = function () {
32492             if (!_actions.length) return '';
32493
32494             var actionDisableds = _actions.map(function (action) {
32495               return action.disabled(context.graph());
32496             }).filter(Boolean);
32497
32498             if (actionDisableds.length === _actions.length) {
32499               // none of the features can be squared
32500               if (new Set(actionDisableds).size > 1) {
32501                 return 'multiple_blockers';
32502               }
32503
32504               return actionDisableds[0];
32505             } else if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
32506               return 'too_large';
32507             } else if (someMissing()) {
32508               return 'not_downloaded';
32509             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32510               return 'connected_to_hidden';
32511             }
32512
32513             return false;
32514
32515             function someMissing() {
32516               if (context.inIntro()) return false;
32517               var osm = context.connection();
32518
32519               if (osm) {
32520                 var missing = _coords.filter(function (loc) {
32521                   return !osm.isDataLoaded(loc);
32522                 });
32523
32524                 if (missing.length) {
32525                   missing.forEach(function (loc) {
32526                     context.loadTileAtLoc(loc);
32527                   });
32528                   return true;
32529                 }
32530               }
32531
32532               return false;
32533             }
32534           };
32535
32536           operation.tooltip = function () {
32537             var disable = operation.disabled();
32538             return disable ? _t('operations.orthogonalize.' + disable + '.' + _amount) : _t('operations.orthogonalize.description.' + _type + '.' + _amount);
32539           };
32540
32541           operation.annotation = function () {
32542             return _t('operations.orthogonalize.annotation.' + _type, {
32543               n: _actions.length
32544             });
32545           };
32546
32547           operation.id = 'orthogonalize';
32548           operation.keys = [_t('operations.orthogonalize.key')];
32549           operation.title = _t('operations.orthogonalize.title');
32550           operation.behavior = behaviorOperation(context).which(operation);
32551           return operation;
32552         }
32553
32554         function operationReflectShort(context, selectedIDs) {
32555           return operationReflect(context, selectedIDs, 'short');
32556         }
32557         function operationReflectLong(context, selectedIDs) {
32558           return operationReflect(context, selectedIDs, 'long');
32559         }
32560         function operationReflect(context, selectedIDs, axis) {
32561           axis = axis || 'long';
32562           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32563           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32564           var coords = nodes.map(function (n) {
32565             return n.loc;
32566           });
32567           var extent = utilTotalExtent(selectedIDs, context.graph());
32568
32569           var operation = function operation() {
32570             var action = actionReflect(selectedIDs, context.projection).useLongAxis(Boolean(axis === 'long'));
32571             context.perform(action, operation.annotation());
32572             window.setTimeout(function () {
32573               context.validator().validate();
32574             }, 300); // after any transition
32575           };
32576
32577           operation.available = function () {
32578             return nodes.length >= 3;
32579           }; // don't cache this because the visible extent could change
32580
32581
32582           operation.disabled = function () {
32583             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32584               return 'too_large';
32585             } else if (someMissing()) {
32586               return 'not_downloaded';
32587             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32588               return 'connected_to_hidden';
32589             } else if (selectedIDs.some(incompleteRelation)) {
32590               return 'incomplete_relation';
32591             }
32592
32593             return false;
32594
32595             function someMissing() {
32596               if (context.inIntro()) return false;
32597               var osm = context.connection();
32598
32599               if (osm) {
32600                 var missing = coords.filter(function (loc) {
32601                   return !osm.isDataLoaded(loc);
32602                 });
32603
32604                 if (missing.length) {
32605                   missing.forEach(function (loc) {
32606                     context.loadTileAtLoc(loc);
32607                   });
32608                   return true;
32609                 }
32610               }
32611
32612               return false;
32613             }
32614
32615             function incompleteRelation(id) {
32616               var entity = context.entity(id);
32617               return entity.type === 'relation' && !entity.isComplete(context.graph());
32618             }
32619           };
32620
32621           operation.tooltip = function () {
32622             var disable = operation.disabled();
32623             return disable ? _t('operations.reflect.' + disable + '.' + multi) : _t('operations.reflect.description.' + axis + '.' + multi);
32624           };
32625
32626           operation.annotation = function () {
32627             return _t('operations.reflect.annotation.' + axis + '.feature', {
32628               n: selectedIDs.length
32629             });
32630           };
32631
32632           operation.id = 'reflect-' + axis;
32633           operation.keys = [_t('operations.reflect.key.' + axis)];
32634           operation.title = _t('operations.reflect.title.' + axis);
32635           operation.behavior = behaviorOperation(context).which(operation);
32636           return operation;
32637         }
32638
32639         function operationMove(context, selectedIDs) {
32640           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32641           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32642           var coords = nodes.map(function (n) {
32643             return n.loc;
32644           });
32645           var extent = utilTotalExtent(selectedIDs, context.graph());
32646
32647           var operation = function operation() {
32648             context.enter(modeMove(context, selectedIDs));
32649           };
32650
32651           operation.available = function () {
32652             return selectedIDs.length > 1 || context.entity(selectedIDs[0]).type !== 'node';
32653           };
32654
32655           operation.disabled = function () {
32656             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32657               return 'too_large';
32658             } else if (someMissing()) {
32659               return 'not_downloaded';
32660             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32661               return 'connected_to_hidden';
32662             } else if (selectedIDs.some(incompleteRelation)) {
32663               return 'incomplete_relation';
32664             }
32665
32666             return false;
32667
32668             function someMissing() {
32669               if (context.inIntro()) return false;
32670               var osm = context.connection();
32671
32672               if (osm) {
32673                 var missing = coords.filter(function (loc) {
32674                   return !osm.isDataLoaded(loc);
32675                 });
32676
32677                 if (missing.length) {
32678                   missing.forEach(function (loc) {
32679                     context.loadTileAtLoc(loc);
32680                   });
32681                   return true;
32682                 }
32683               }
32684
32685               return false;
32686             }
32687
32688             function incompleteRelation(id) {
32689               var entity = context.entity(id);
32690               return entity.type === 'relation' && !entity.isComplete(context.graph());
32691             }
32692           };
32693
32694           operation.tooltip = function () {
32695             var disable = operation.disabled();
32696             return disable ? _t('operations.move.' + disable + '.' + multi) : _t('operations.move.description.' + multi);
32697           };
32698
32699           operation.annotation = function () {
32700             return selectedIDs.length === 1 ? _t('operations.move.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.move.annotation.feature', {
32701               n: selectedIDs.length
32702             });
32703           };
32704
32705           operation.id = 'move';
32706           operation.keys = [_t('operations.move.key')];
32707           operation.title = _t('operations.move.title');
32708           operation.behavior = behaviorOperation(context).which(operation);
32709           operation.mouseOnly = true;
32710           return operation;
32711         }
32712
32713         function modeRotate(context, entityIDs) {
32714           var mode = {
32715             id: 'rotate',
32716             button: 'browse'
32717           };
32718           var keybinding = utilKeybinding('rotate');
32719           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];
32720           var annotation = entityIDs.length === 1 ? _t('operations.rotate.annotation.' + context.graph().geometry(entityIDs[0])) : _t('operations.rotate.annotation.feature', {
32721             n: entityIDs.length
32722           });
32723
32724           var _prevGraph;
32725
32726           var _prevAngle;
32727
32728           var _prevTransform;
32729
32730           var _pivot;
32731
32732           function doRotate() {
32733             var fn;
32734
32735             if (context.graph() !== _prevGraph) {
32736               fn = context.perform;
32737             } else {
32738               fn = context.replace;
32739             } // projection changed, recalculate _pivot
32740
32741
32742             var projection = context.projection;
32743             var currTransform = projection.transform();
32744
32745             if (!_prevTransform || currTransform.k !== _prevTransform.k || currTransform.x !== _prevTransform.x || currTransform.y !== _prevTransform.y) {
32746               var nodes = utilGetAllNodes(entityIDs, context.graph());
32747               var points = nodes.map(function (n) {
32748                 return projection(n.loc);
32749               });
32750               _pivot = getPivot(points);
32751               _prevAngle = undefined;
32752             }
32753
32754             var currMouse = context.map().mouse();
32755             var currAngle = Math.atan2(currMouse[1] - _pivot[1], currMouse[0] - _pivot[0]);
32756             if (typeof _prevAngle === 'undefined') _prevAngle = currAngle;
32757             var delta = currAngle - _prevAngle;
32758             fn(actionRotate(entityIDs, _pivot, delta, projection));
32759             _prevTransform = currTransform;
32760             _prevAngle = currAngle;
32761             _prevGraph = context.graph();
32762           }
32763
32764           function getPivot(points) {
32765             var _pivot;
32766
32767             if (points.length === 1) {
32768               _pivot = points[0];
32769             } else if (points.length === 2) {
32770               _pivot = geoVecInterp(points[0], points[1], 0.5);
32771             } else {
32772               var polygonHull = d3_polygonHull(points);
32773
32774               if (polygonHull.length === 2) {
32775                 _pivot = geoVecInterp(points[0], points[1], 0.5);
32776               } else {
32777                 _pivot = d3_polygonCentroid(d3_polygonHull(points));
32778               }
32779             }
32780
32781             return _pivot;
32782           }
32783
32784           function finish(d3_event) {
32785             d3_event.stopPropagation();
32786             context.replace(actionNoop(), annotation);
32787             context.enter(modeSelect(context, entityIDs));
32788           }
32789
32790           function cancel() {
32791             context.pop();
32792             context.enter(modeSelect(context, entityIDs));
32793           }
32794
32795           function undone() {
32796             context.enter(modeBrowse(context));
32797           }
32798
32799           mode.enter = function () {
32800             context.features().forceVisible(entityIDs);
32801             behaviors.forEach(context.install);
32802             context.surface().on('mousemove.rotate', doRotate).on('click.rotate', finish);
32803             context.history().on('undone.rotate', undone);
32804             keybinding.on('⎋', cancel).on('↩', finish);
32805             select(document).call(keybinding);
32806           };
32807
32808           mode.exit = function () {
32809             behaviors.forEach(context.uninstall);
32810             context.surface().on('mousemove.rotate', null).on('click.rotate', null);
32811             context.history().on('undone.rotate', null);
32812             select(document).call(keybinding.unbind);
32813             context.features().forceVisible([]);
32814           };
32815
32816           mode.selectedIDs = function () {
32817             if (!arguments.length) return entityIDs; // no assign
32818
32819             return mode;
32820           };
32821
32822           return mode;
32823         }
32824
32825         function operationRotate(context, selectedIDs) {
32826           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32827           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32828           var coords = nodes.map(function (n) {
32829             return n.loc;
32830           });
32831           var extent = utilTotalExtent(selectedIDs, context.graph());
32832
32833           var operation = function operation() {
32834             context.enter(modeRotate(context, selectedIDs));
32835           };
32836
32837           operation.available = function () {
32838             return nodes.length >= 2;
32839           };
32840
32841           operation.disabled = function () {
32842             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32843               return 'too_large';
32844             } else if (someMissing()) {
32845               return 'not_downloaded';
32846             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32847               return 'connected_to_hidden';
32848             } else if (selectedIDs.some(incompleteRelation)) {
32849               return 'incomplete_relation';
32850             }
32851
32852             return false;
32853
32854             function someMissing() {
32855               if (context.inIntro()) return false;
32856               var osm = context.connection();
32857
32858               if (osm) {
32859                 var missing = coords.filter(function (loc) {
32860                   return !osm.isDataLoaded(loc);
32861                 });
32862
32863                 if (missing.length) {
32864                   missing.forEach(function (loc) {
32865                     context.loadTileAtLoc(loc);
32866                   });
32867                   return true;
32868                 }
32869               }
32870
32871               return false;
32872             }
32873
32874             function incompleteRelation(id) {
32875               var entity = context.entity(id);
32876               return entity.type === 'relation' && !entity.isComplete(context.graph());
32877             }
32878           };
32879
32880           operation.tooltip = function () {
32881             var disable = operation.disabled();
32882             return disable ? _t('operations.rotate.' + disable + '.' + multi) : _t('operations.rotate.description.' + multi);
32883           };
32884
32885           operation.annotation = function () {
32886             return selectedIDs.length === 1 ? _t('operations.rotate.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.rotate.annotation.feature', {
32887               n: selectedIDs.length
32888             });
32889           };
32890
32891           operation.id = 'rotate';
32892           operation.keys = [_t('operations.rotate.key')];
32893           operation.title = _t('operations.rotate.title');
32894           operation.behavior = behaviorOperation(context).which(operation);
32895           operation.mouseOnly = true;
32896           return operation;
32897         }
32898
32899         function modeMove(context, entityIDs, baseGraph) {
32900           var mode = {
32901             id: 'move',
32902             button: 'browse'
32903           };
32904           var keybinding = utilKeybinding('move');
32905           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];
32906           var annotation = entityIDs.length === 1 ? _t('operations.move.annotation.' + context.graph().geometry(entityIDs[0])) : _t('operations.move.annotation.feature', {
32907             n: entityIDs.length
32908           });
32909
32910           var _prevGraph;
32911
32912           var _cache;
32913
32914           var _origin;
32915
32916           var _nudgeInterval;
32917
32918           function doMove(nudge) {
32919             nudge = nudge || [0, 0];
32920             var fn;
32921
32922             if (_prevGraph !== context.graph()) {
32923               _cache = {};
32924               _origin = context.map().mouseCoordinates();
32925               fn = context.perform;
32926             } else {
32927               fn = context.overwrite;
32928             }
32929
32930             var currMouse = context.map().mouse();
32931             var origMouse = context.projection(_origin);
32932             var delta = geoVecSubtract(geoVecSubtract(currMouse, origMouse), nudge);
32933             fn(actionMove(entityIDs, delta, context.projection, _cache));
32934             _prevGraph = context.graph();
32935           }
32936
32937           function startNudge(nudge) {
32938             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
32939             _nudgeInterval = window.setInterval(function () {
32940               context.map().pan(nudge);
32941               doMove(nudge);
32942             }, 50);
32943           }
32944
32945           function stopNudge() {
32946             if (_nudgeInterval) {
32947               window.clearInterval(_nudgeInterval);
32948               _nudgeInterval = null;
32949             }
32950           }
32951
32952           function move() {
32953             doMove();
32954             var nudge = geoViewportEdge(context.map().mouse(), context.map().dimensions());
32955
32956             if (nudge) {
32957               startNudge(nudge);
32958             } else {
32959               stopNudge();
32960             }
32961           }
32962
32963           function finish(d3_event) {
32964             d3_event.stopPropagation();
32965             context.replace(actionNoop(), annotation);
32966             context.enter(modeSelect(context, entityIDs));
32967             stopNudge();
32968           }
32969
32970           function cancel() {
32971             if (baseGraph) {
32972               while (context.graph() !== baseGraph) {
32973                 context.pop();
32974               }
32975
32976               context.enter(modeBrowse(context));
32977             } else {
32978               context.pop();
32979               context.enter(modeSelect(context, entityIDs));
32980             }
32981
32982             stopNudge();
32983           }
32984
32985           function undone() {
32986             context.enter(modeBrowse(context));
32987           }
32988
32989           mode.enter = function () {
32990             _origin = context.map().mouseCoordinates();
32991             _prevGraph = null;
32992             _cache = {};
32993             context.features().forceVisible(entityIDs);
32994             behaviors.forEach(context.install);
32995             context.surface().on('mousemove.move', move).on('click.move', finish);
32996             context.history().on('undone.move', undone);
32997             keybinding.on('⎋', cancel).on('↩', finish);
32998             select(document).call(keybinding);
32999           };
33000
33001           mode.exit = function () {
33002             stopNudge();
33003             behaviors.forEach(function (behavior) {
33004               context.uninstall(behavior);
33005             });
33006             context.surface().on('mousemove.move', null).on('click.move', null);
33007             context.history().on('undone.move', null);
33008             select(document).call(keybinding.unbind);
33009             context.features().forceVisible([]);
33010           };
33011
33012           mode.selectedIDs = function () {
33013             if (!arguments.length) return entityIDs; // no assign
33014
33015             return mode;
33016           };
33017
33018           return mode;
33019         }
33020
33021         function behaviorPaste(context) {
33022           function doPaste(d3_event) {
33023             // prevent paste during low zoom selection
33024             if (!context.map().withinEditableZoom()) return;
33025             d3_event.preventDefault();
33026             var baseGraph = context.graph();
33027             var mouse = context.map().mouse();
33028             var projection = context.projection;
33029             var viewport = geoExtent(projection.clipExtent()).polygon();
33030             if (!geoPointInPolygon(mouse, viewport)) return;
33031             var oldIDs = context.copyIDs();
33032             if (!oldIDs.length) return;
33033             var extent = geoExtent();
33034             var oldGraph = context.copyGraph();
33035             var newIDs = [];
33036             var action = actionCopyEntities(oldIDs, oldGraph);
33037             context.perform(action);
33038             var copies = action.copies();
33039             var originals = new Set();
33040             Object.values(copies).forEach(function (entity) {
33041               originals.add(entity.id);
33042             });
33043
33044             for (var id in copies) {
33045               var oldEntity = oldGraph.entity(id);
33046               var newEntity = copies[id];
33047
33048               extent._extend(oldEntity.extent(oldGraph)); // Exclude child nodes from newIDs if their parent way was also copied.
33049
33050
33051               var parents = context.graph().parentWays(newEntity);
33052               var parentCopied = parents.some(function (parent) {
33053                 return originals.has(parent.id);
33054               });
33055
33056               if (!parentCopied) {
33057                 newIDs.push(newEntity.id);
33058               }
33059             } // Put pasted objects where mouse pointer is..
33060
33061
33062             var copyPoint = context.copyLonLat() && projection(context.copyLonLat()) || projection(extent.center());
33063             var delta = geoVecSubtract(mouse, copyPoint);
33064             context.perform(actionMove(newIDs, delta, projection));
33065             context.enter(modeMove(context, newIDs, baseGraph));
33066           }
33067
33068           function behavior() {
33069             context.keybinding().on(uiCmd('⌘V'), doPaste);
33070             return behavior;
33071           }
33072
33073           behavior.off = function () {
33074             context.keybinding().off(uiCmd('⌘V'));
33075           };
33076
33077           return behavior;
33078         }
33079
33080         // `String.prototype.repeat` method
33081         // https://tc39.github.io/ecma262/#sec-string.prototype.repeat
33082         _export({ target: 'String', proto: true }, {
33083           repeat: stringRepeat
33084         });
33085
33086         /*
33087             `behaviorDrag` is like `d3_behavior.drag`, with the following differences:
33088
33089             * The `origin` function is expected to return an [x, y] tuple rather than an
33090               {x, y} object.
33091             * The events are `start`, `move`, and `end`.
33092               (https://github.com/mbostock/d3/issues/563)
33093             * The `start` event is not dispatched until the first cursor movement occurs.
33094               (https://github.com/mbostock/d3/pull/368)
33095             * The `move` event has a `point` and `delta` [x, y] tuple properties rather
33096               than `x`, `y`, `dx`, and `dy` properties.
33097             * The `end` event is not dispatched if no movement occurs.
33098             * An `off` function is available that unbinds the drag's internal event handlers.
33099          */
33100
33101         function behaviorDrag() {
33102           var dispatch$1 = dispatch('start', 'move', 'end'); // see also behaviorSelect
33103
33104           var _tolerancePx = 1; // keep this low to facilitate pixel-perfect micromapping
33105
33106           var _penTolerancePx = 4; // styluses can be touchy so require greater movement - #1981
33107
33108           var _origin = null;
33109           var _selector = '';
33110
33111           var _targetNode;
33112
33113           var _targetEntity;
33114
33115           var _surface;
33116
33117           var _pointerId; // use pointer events on supported platforms; fallback to mouse events
33118
33119
33120           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
33121
33122           var d3_event_userSelectProperty = utilPrefixCSSProperty('UserSelect');
33123
33124           var d3_event_userSelectSuppress = function d3_event_userSelectSuppress() {
33125             var selection$1 = selection();
33126             var select = selection$1.style(d3_event_userSelectProperty);
33127             selection$1.style(d3_event_userSelectProperty, 'none');
33128             return function () {
33129               selection$1.style(d3_event_userSelectProperty, select);
33130             };
33131           };
33132
33133           function pointerdown(d3_event) {
33134             if (_pointerId) return;
33135             _pointerId = d3_event.pointerId || 'mouse';
33136             _targetNode = this; // only force reflow once per drag
33137
33138             var pointerLocGetter = utilFastMouse(_surface || _targetNode.parentNode);
33139             var offset;
33140             var startOrigin = pointerLocGetter(d3_event);
33141             var started = false;
33142             var selectEnable = d3_event_userSelectSuppress();
33143             select(window).on(_pointerPrefix + 'move.drag', pointermove).on(_pointerPrefix + 'up.drag pointercancel.drag', pointerup, true);
33144
33145             if (_origin) {
33146               offset = _origin.call(_targetNode, _targetEntity);
33147               offset = [offset[0] - startOrigin[0], offset[1] - startOrigin[1]];
33148             } else {
33149               offset = [0, 0];
33150             }
33151
33152             d3_event.stopPropagation();
33153
33154             function pointermove(d3_event) {
33155               if (_pointerId !== (d3_event.pointerId || 'mouse')) return;
33156               var p = pointerLocGetter(d3_event);
33157
33158               if (!started) {
33159                 var dist = geoVecLength(startOrigin, p);
33160                 var tolerance = d3_event.pointerType === 'pen' ? _penTolerancePx : _tolerancePx; // don't start until the drag has actually moved somewhat
33161
33162                 if (dist < tolerance) return;
33163                 started = true;
33164                 dispatch$1.call('start', this, d3_event, _targetEntity); // Don't send a `move` event in the same cycle as `start` since dragging
33165                 // a midpoint will convert the target to a node.
33166               } else {
33167                 startOrigin = p;
33168                 d3_event.stopPropagation();
33169                 d3_event.preventDefault();
33170                 var dx = p[0] - startOrigin[0];
33171                 var dy = p[1] - startOrigin[1];
33172                 dispatch$1.call('move', this, d3_event, _targetEntity, [p[0] + offset[0], p[1] + offset[1]], [dx, dy]);
33173               }
33174             }
33175
33176             function pointerup(d3_event) {
33177               if (_pointerId !== (d3_event.pointerId || 'mouse')) return;
33178               _pointerId = null;
33179
33180               if (started) {
33181                 dispatch$1.call('end', this, d3_event, _targetEntity);
33182                 d3_event.preventDefault();
33183               }
33184
33185               select(window).on(_pointerPrefix + 'move.drag', null).on(_pointerPrefix + 'up.drag pointercancel.drag', null);
33186               selectEnable();
33187             }
33188           }
33189
33190           function behavior(selection) {
33191             var matchesSelector = utilPrefixDOMProperty('matchesSelector');
33192             var delegate = pointerdown;
33193
33194             if (_selector) {
33195               delegate = function delegate(d3_event) {
33196                 var root = this;
33197                 var target = d3_event.target;
33198
33199                 for (; target && target !== root; target = target.parentNode) {
33200                   var datum = target.__data__;
33201                   _targetEntity = datum instanceof osmNote ? datum : datum && datum.properties && datum.properties.entity;
33202
33203                   if (_targetEntity && target[matchesSelector](_selector)) {
33204                     return pointerdown.call(target, d3_event);
33205                   }
33206                 }
33207               };
33208             }
33209
33210             selection.on(_pointerPrefix + 'down.drag' + _selector, delegate);
33211           }
33212
33213           behavior.off = function (selection) {
33214             selection.on(_pointerPrefix + 'down.drag' + _selector, null);
33215           };
33216
33217           behavior.selector = function (_) {
33218             if (!arguments.length) return _selector;
33219             _selector = _;
33220             return behavior;
33221           };
33222
33223           behavior.origin = function (_) {
33224             if (!arguments.length) return _origin;
33225             _origin = _;
33226             return behavior;
33227           };
33228
33229           behavior.cancel = function () {
33230             select(window).on(_pointerPrefix + 'move.drag', null).on(_pointerPrefix + 'up.drag pointercancel.drag', null);
33231             return behavior;
33232           };
33233
33234           behavior.targetNode = function (_) {
33235             if (!arguments.length) return _targetNode;
33236             _targetNode = _;
33237             return behavior;
33238           };
33239
33240           behavior.targetEntity = function (_) {
33241             if (!arguments.length) return _targetEntity;
33242             _targetEntity = _;
33243             return behavior;
33244           };
33245
33246           behavior.surface = function (_) {
33247             if (!arguments.length) return _surface;
33248             _surface = _;
33249             return behavior;
33250           };
33251
33252           return utilRebind(behavior, dispatch$1, 'on');
33253         }
33254
33255         function modeDragNode(context) {
33256           var mode = {
33257             id: 'drag-node',
33258             button: 'browse'
33259           };
33260           var hover = behaviorHover(context).altDisables(true).on('hover', context.ui().sidebar.hover);
33261           var edit = behaviorEdit(context);
33262
33263           var _nudgeInterval;
33264
33265           var _restoreSelectedIDs = [];
33266           var _wasMidpoint = false;
33267           var _isCancelled = false;
33268
33269           var _activeEntity;
33270
33271           var _startLoc;
33272
33273           var _lastLoc;
33274
33275           function startNudge(d3_event, entity, nudge) {
33276             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
33277             _nudgeInterval = window.setInterval(function () {
33278               context.map().pan(nudge);
33279               doMove(d3_event, entity, nudge);
33280             }, 50);
33281           }
33282
33283           function stopNudge() {
33284             if (_nudgeInterval) {
33285               window.clearInterval(_nudgeInterval);
33286               _nudgeInterval = null;
33287             }
33288           }
33289
33290           function moveAnnotation(entity) {
33291             return _t('operations.move.annotation.' + entity.geometry(context.graph()));
33292           }
33293
33294           function connectAnnotation(nodeEntity, targetEntity) {
33295             var nodeGeometry = nodeEntity.geometry(context.graph());
33296             var targetGeometry = targetEntity.geometry(context.graph());
33297
33298             if (nodeGeometry === 'vertex' && targetGeometry === 'vertex') {
33299               var nodeParentWayIDs = context.graph().parentWays(nodeEntity);
33300               var targetParentWayIDs = context.graph().parentWays(targetEntity);
33301               var sharedParentWays = utilArrayIntersection(nodeParentWayIDs, targetParentWayIDs); // if both vertices are part of the same way
33302
33303               if (sharedParentWays.length !== 0) {
33304                 // if the nodes are next to each other, they are merged
33305                 if (sharedParentWays[0].areAdjacent(nodeEntity.id, targetEntity.id)) {
33306                   return _t('operations.connect.annotation.from_vertex.to_adjacent_vertex');
33307                 }
33308
33309                 return _t('operations.connect.annotation.from_vertex.to_sibling_vertex');
33310               }
33311             }
33312
33313             return _t('operations.connect.annotation.from_' + nodeGeometry + '.to_' + targetGeometry);
33314           }
33315
33316           function shouldSnapToNode(target) {
33317             if (!_activeEntity) return false;
33318             return _activeEntity.geometry(context.graph()) !== 'vertex' || target.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(target, context.graph());
33319           }
33320
33321           function origin(entity) {
33322             return context.projection(entity.loc);
33323           }
33324
33325           function keydown(d3_event) {
33326             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
33327               if (context.surface().classed('nope')) {
33328                 context.surface().classed('nope-suppressed', true);
33329               }
33330
33331               context.surface().classed('nope', false).classed('nope-disabled', true);
33332             }
33333           }
33334
33335           function keyup(d3_event) {
33336             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
33337               if (context.surface().classed('nope-suppressed')) {
33338                 context.surface().classed('nope', true);
33339               }
33340
33341               context.surface().classed('nope-suppressed', false).classed('nope-disabled', false);
33342             }
33343           }
33344
33345           function start(d3_event, entity) {
33346             _wasMidpoint = entity.type === 'midpoint';
33347             var hasHidden = context.features().hasHiddenConnections(entity, context.graph());
33348             _isCancelled = !context.editable() || d3_event.shiftKey || hasHidden;
33349
33350             if (_isCancelled) {
33351               if (hasHidden) {
33352                 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('modes.drag_node.connected_to_hidden'))();
33353               }
33354
33355               return drag.cancel();
33356             }
33357
33358             if (_wasMidpoint) {
33359               var midpoint = entity;
33360               entity = osmNode();
33361               context.perform(actionAddMidpoint(midpoint, entity));
33362               entity = context.entity(entity.id); // get post-action entity
33363
33364               var vertex = context.surface().selectAll('.' + entity.id);
33365               drag.targetNode(vertex.node()).targetEntity(entity);
33366             } else {
33367               context.perform(actionNoop());
33368             }
33369
33370             _activeEntity = entity;
33371             _startLoc = entity.loc;
33372             hover.ignoreVertex(entity.geometry(context.graph()) === 'vertex');
33373             context.surface().selectAll('.' + _activeEntity.id).classed('active', true);
33374             context.enter(mode);
33375           } // related code
33376           // - `behavior/draw.js` `datum()`
33377
33378
33379           function datum(d3_event) {
33380             if (!d3_event || d3_event.altKey) {
33381               return {};
33382             } else {
33383               // When dragging, snap only to touch targets..
33384               // (this excludes area fills and active drawing elements)
33385               var d = d3_event.target.__data__;
33386               return d && d.properties && d.properties.target ? d : {};
33387             }
33388           }
33389
33390           function doMove(d3_event, entity, nudge) {
33391             nudge = nudge || [0, 0];
33392             var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
33393             var currMouse = geoVecSubtract(currPoint, nudge);
33394             var loc = context.projection.invert(currMouse);
33395             var target, edge;
33396
33397             if (!_nudgeInterval) {
33398               // If not nudging at the edge of the viewport, try to snap..
33399               // related code
33400               // - `mode/drag_node.js`     `doMove()`
33401               // - `behavior/draw.js`      `click()`
33402               // - `behavior/draw_way.js`  `move()`
33403               var d = datum(d3_event);
33404               target = d && d.properties && d.properties.entity;
33405               var targetLoc = target && target.loc;
33406               var targetNodes = d && d.properties && d.properties.nodes;
33407
33408               if (targetLoc) {
33409                 // snap to node/vertex - a point target with `.loc`
33410                 if (shouldSnapToNode(target)) {
33411                   loc = targetLoc;
33412                 }
33413               } else if (targetNodes) {
33414                 // snap to way - a line target with `.nodes`
33415                 edge = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, end.id);
33416
33417                 if (edge) {
33418                   loc = edge.loc;
33419                 }
33420               }
33421             }
33422
33423             context.replace(actionMoveNode(entity.id, loc)); // Below here: validations
33424
33425             var isInvalid = false; // Check if this connection to `target` could cause relations to break..
33426
33427             if (target) {
33428               isInvalid = hasRelationConflict(entity, target, edge, context.graph());
33429             } // Check if this drag causes the geometry to break..
33430
33431
33432             if (!isInvalid) {
33433               isInvalid = hasInvalidGeometry(entity, context.graph());
33434             }
33435
33436             var nope = context.surface().classed('nope');
33437
33438             if (isInvalid === 'relation' || isInvalid === 'restriction') {
33439               if (!nope) {
33440                 // about to nope - show hint
33441                 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('operations.connect.' + isInvalid, {
33442                   relation: _mainPresetIndex.item('type/restriction').name()
33443                 }))();
33444               }
33445             } else if (isInvalid) {
33446               var errorID = isInvalid === 'line' ? 'lines' : 'areas';
33447               context.ui().flash.duration(3000).iconName('#iD-icon-no').label(_t('self_intersection.error.' + errorID))();
33448             } else {
33449               if (nope) {
33450                 // about to un-nope, remove hint
33451                 context.ui().flash.duration(1).label('')();
33452               }
33453             }
33454
33455             var nopeDisabled = context.surface().classed('nope-disabled');
33456
33457             if (nopeDisabled) {
33458               context.surface().classed('nope', false).classed('nope-suppressed', isInvalid);
33459             } else {
33460               context.surface().classed('nope', isInvalid).classed('nope-suppressed', false);
33461             }
33462
33463             _lastLoc = loc;
33464           } // Uses `actionConnect.disabled()` to know whether this connection is ok..
33465
33466
33467           function hasRelationConflict(entity, target, edge, graph) {
33468             var testGraph = graph.update(); // copy
33469             // if snapping to way - add midpoint there and consider that the target..
33470
33471             if (edge) {
33472               var midpoint = osmNode();
33473               var action = actionAddMidpoint({
33474                 loc: edge.loc,
33475                 edge: [target.nodes[edge.index - 1], target.nodes[edge.index]]
33476               }, midpoint);
33477               testGraph = action(testGraph);
33478               target = midpoint;
33479             } // can we connect to it?
33480
33481
33482             var ids = [entity.id, target.id];
33483             return actionConnect(ids).disabled(testGraph);
33484           }
33485
33486           function hasInvalidGeometry(entity, graph) {
33487             var parents = graph.parentWays(entity);
33488             var i, j, k;
33489
33490             for (i = 0; i < parents.length; i++) {
33491               var parent = parents[i];
33492               var nodes = [];
33493               var activeIndex = null; // which multipolygon ring contains node being dragged
33494               // test any parent multipolygons for valid geometry
33495
33496               var relations = graph.parentRelations(parent);
33497
33498               for (j = 0; j < relations.length; j++) {
33499                 if (!relations[j].isMultipolygon()) continue;
33500                 var rings = osmJoinWays(relations[j].members, graph); // find active ring and test it for self intersections
33501
33502                 for (k = 0; k < rings.length; k++) {
33503                   nodes = rings[k].nodes;
33504
33505                   if (nodes.find(function (n) {
33506                     return n.id === entity.id;
33507                   })) {
33508                     activeIndex = k;
33509
33510                     if (geoHasSelfIntersections(nodes, entity.id)) {
33511                       return 'multipolygonMember';
33512                     }
33513                   }
33514
33515                   rings[k].coords = nodes.map(function (n) {
33516                     return n.loc;
33517                   });
33518                 } // test active ring for intersections with other rings in the multipolygon
33519
33520
33521                 for (k = 0; k < rings.length; k++) {
33522                   if (k === activeIndex) continue; // make sure active ring doesn't cross passive rings
33523
33524                   if (geoHasLineIntersections(rings[activeIndex].nodes, rings[k].nodes, entity.id)) {
33525                     return 'multipolygonRing';
33526                   }
33527                 }
33528               } // If we still haven't tested this node's parent way for self-intersections.
33529               // (because it's not a member of a multipolygon), test it now.
33530
33531
33532               if (activeIndex === null) {
33533                 nodes = parent.nodes.map(function (nodeID) {
33534                   return graph.entity(nodeID);
33535                 });
33536
33537                 if (nodes.length && geoHasSelfIntersections(nodes, entity.id)) {
33538                   return parent.geometry(graph);
33539                 }
33540               }
33541             }
33542
33543             return false;
33544           }
33545
33546           function move(d3_event, entity, point) {
33547             if (_isCancelled) return;
33548             d3_event.stopPropagation();
33549             context.surface().classed('nope-disabled', d3_event.altKey);
33550             _lastLoc = context.projection.invert(point);
33551             doMove(d3_event, entity);
33552             var nudge = geoViewportEdge(point, context.map().dimensions());
33553
33554             if (nudge) {
33555               startNudge(d3_event, entity, nudge);
33556             } else {
33557               stopNudge();
33558             }
33559           }
33560
33561           function end(d3_event, entity) {
33562             if (_isCancelled) return;
33563             var wasPoint = entity.geometry(context.graph()) === 'point';
33564             var d = datum(d3_event);
33565             var nope = d && d.properties && d.properties.nope || context.surface().classed('nope');
33566             var target = d && d.properties && d.properties.entity; // entity to snap to
33567
33568             if (nope) {
33569               // bounce back
33570               context.perform(_actionBounceBack(entity.id, _startLoc));
33571             } else if (target && target.type === 'way') {
33572               var choice = geoChooseEdge(context.graph().childNodes(target), context.map().mouse(), context.projection, entity.id);
33573               context.replace(actionAddMidpoint({
33574                 loc: choice.loc,
33575                 edge: [target.nodes[choice.index - 1], target.nodes[choice.index]]
33576               }, entity), connectAnnotation(entity, target));
33577             } else if (target && target.type === 'node' && shouldSnapToNode(target)) {
33578               context.replace(actionConnect([target.id, entity.id]), connectAnnotation(entity, target));
33579             } else if (_wasMidpoint) {
33580               context.replace(actionNoop(), _t('operations.add.annotation.vertex'));
33581             } else {
33582               context.replace(actionNoop(), moveAnnotation(entity));
33583             }
33584
33585             if (wasPoint) {
33586               context.enter(modeSelect(context, [entity.id]));
33587             } else {
33588               var reselection = _restoreSelectedIDs.filter(function (id) {
33589                 return context.graph().hasEntity(id);
33590               });
33591
33592               if (reselection.length) {
33593                 context.enter(modeSelect(context, reselection));
33594               } else {
33595                 context.enter(modeBrowse(context));
33596               }
33597             }
33598           }
33599
33600           function _actionBounceBack(nodeID, toLoc) {
33601             var moveNode = actionMoveNode(nodeID, toLoc);
33602
33603             var action = function action(graph, t) {
33604               // last time through, pop off the bounceback perform.
33605               // it will then overwrite the initial perform with a moveNode that does nothing
33606               if (t === 1) context.pop();
33607               return moveNode(graph, t);
33608             };
33609
33610             action.transitionable = true;
33611             return action;
33612           }
33613
33614           function cancel() {
33615             drag.cancel();
33616             context.enter(modeBrowse(context));
33617           }
33618
33619           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);
33620
33621           mode.enter = function () {
33622             context.install(hover);
33623             context.install(edit);
33624             select(window).on('keydown.dragNode', keydown).on('keyup.dragNode', keyup);
33625             context.history().on('undone.drag-node', cancel);
33626           };
33627
33628           mode.exit = function () {
33629             context.ui().sidebar.hover.cancel();
33630             context.uninstall(hover);
33631             context.uninstall(edit);
33632             select(window).on('keydown.dragNode', null).on('keyup.dragNode', null);
33633             context.history().on('undone.drag-node', null);
33634             _activeEntity = null;
33635             context.surface().classed('nope', false).classed('nope-suppressed', false).classed('nope-disabled', false).selectAll('.active').classed('active', false);
33636             stopNudge();
33637           };
33638
33639           mode.selectedIDs = function () {
33640             if (!arguments.length) return _activeEntity ? [_activeEntity.id] : []; // no assign
33641
33642             return mode;
33643           };
33644
33645           mode.activeID = function () {
33646             if (!arguments.length) return _activeEntity && _activeEntity.id; // no assign
33647
33648             return mode;
33649           };
33650
33651           mode.restoreSelectedIDs = function (_) {
33652             if (!arguments.length) return _restoreSelectedIDs;
33653             _restoreSelectedIDs = _;
33654             return mode;
33655           };
33656
33657           mode.behavior = drag;
33658           return mode;
33659         }
33660
33661         // Safari bug https://bugs.webkit.org/show_bug.cgi?id=200829
33662         var NON_GENERIC = !!nativePromiseConstructor && fails(function () {
33663           nativePromiseConstructor.prototype['finally'].call({ then: function () { /* empty */ } }, function () { /* empty */ });
33664         });
33665
33666         // `Promise.prototype.finally` method
33667         // https://tc39.github.io/ecma262/#sec-promise.prototype.finally
33668         _export({ target: 'Promise', proto: true, real: true, forced: NON_GENERIC }, {
33669           'finally': function (onFinally) {
33670             var C = speciesConstructor(this, getBuiltIn('Promise'));
33671             var isFunction = typeof onFinally == 'function';
33672             return this.then(
33673               isFunction ? function (x) {
33674                 return promiseResolve(C, onFinally()).then(function () { return x; });
33675               } : onFinally,
33676               isFunction ? function (e) {
33677                 return promiseResolve(C, onFinally()).then(function () { throw e; });
33678               } : onFinally
33679             );
33680           }
33681         });
33682
33683         // patch native Promise.prototype for native async functions
33684         if ( typeof nativePromiseConstructor == 'function' && !nativePromiseConstructor.prototype['finally']) {
33685           redefine(nativePromiseConstructor.prototype, 'finally', getBuiltIn('Promise').prototype['finally']);
33686         }
33687
33688         // @@search logic
33689         fixRegexpWellKnownSymbolLogic('search', 1, function (SEARCH, nativeSearch, maybeCallNative) {
33690           return [
33691             // `String.prototype.search` method
33692             // https://tc39.github.io/ecma262/#sec-string.prototype.search
33693             function search(regexp) {
33694               var O = requireObjectCoercible(this);
33695               var searcher = regexp == undefined ? undefined : regexp[SEARCH];
33696               return searcher !== undefined ? searcher.call(regexp, O) : new RegExp(regexp)[SEARCH](String(O));
33697             },
33698             // `RegExp.prototype[@@search]` method
33699             // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@search
33700             function (regexp) {
33701               var res = maybeCallNative(nativeSearch, regexp, this);
33702               if (res.done) return res.value;
33703
33704               var rx = anObject(regexp);
33705               var S = String(this);
33706
33707               var previousLastIndex = rx.lastIndex;
33708               if (!sameValue(previousLastIndex, 0)) rx.lastIndex = 0;
33709               var result = regexpExecAbstract(rx, S);
33710               if (!sameValue(rx.lastIndex, previousLastIndex)) rx.lastIndex = previousLastIndex;
33711               return result === null ? -1 : result.index;
33712             }
33713           ];
33714         });
33715
33716         function quickselect$1(arr, k, left, right, compare) {
33717           quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
33718         }
33719
33720         function quickselectStep(arr, k, left, right, compare) {
33721           while (right > left) {
33722             if (right - left > 600) {
33723               var n = right - left + 1;
33724               var m = k - left + 1;
33725               var z = Math.log(n);
33726               var s = 0.5 * Math.exp(2 * z / 3);
33727               var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
33728               var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
33729               var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
33730               quickselectStep(arr, k, newLeft, newRight, compare);
33731             }
33732
33733             var t = arr[k];
33734             var i = left;
33735             var j = right;
33736             swap$1(arr, left, k);
33737             if (compare(arr[right], t) > 0) swap$1(arr, left, right);
33738
33739             while (i < j) {
33740               swap$1(arr, i, j);
33741               i++;
33742               j--;
33743
33744               while (compare(arr[i], t) < 0) {
33745                 i++;
33746               }
33747
33748               while (compare(arr[j], t) > 0) {
33749                 j--;
33750               }
33751             }
33752
33753             if (compare(arr[left], t) === 0) swap$1(arr, left, j);else {
33754               j++;
33755               swap$1(arr, j, right);
33756             }
33757             if (j <= k) left = j + 1;
33758             if (k <= j) right = j - 1;
33759           }
33760         }
33761
33762         function swap$1(arr, i, j) {
33763           var tmp = arr[i];
33764           arr[i] = arr[j];
33765           arr[j] = tmp;
33766         }
33767
33768         function defaultCompare(a, b) {
33769           return a < b ? -1 : a > b ? 1 : 0;
33770         }
33771
33772         var RBush = /*#__PURE__*/function () {
33773           function RBush() {
33774             var maxEntries = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 9;
33775
33776             _classCallCheck(this, RBush);
33777
33778             // max entries in a node is 9 by default; min node fill is 40% for best performance
33779             this._maxEntries = Math.max(4, maxEntries);
33780             this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
33781             this.clear();
33782           }
33783
33784           _createClass(RBush, [{
33785             key: "all",
33786             value: function all() {
33787               return this._all(this.data, []);
33788             }
33789           }, {
33790             key: "search",
33791             value: function search(bbox) {
33792               var node = this.data;
33793               var result = [];
33794               if (!intersects(bbox, node)) return result;
33795               var toBBox = this.toBBox;
33796               var nodesToSearch = [];
33797
33798               while (node) {
33799                 for (var i = 0; i < node.children.length; i++) {
33800                   var child = node.children[i];
33801                   var childBBox = node.leaf ? toBBox(child) : child;
33802
33803                   if (intersects(bbox, childBBox)) {
33804                     if (node.leaf) result.push(child);else if (contains(bbox, childBBox)) this._all(child, result);else nodesToSearch.push(child);
33805                   }
33806                 }
33807
33808                 node = nodesToSearch.pop();
33809               }
33810
33811               return result;
33812             }
33813           }, {
33814             key: "collides",
33815             value: function collides(bbox) {
33816               var node = this.data;
33817               if (!intersects(bbox, node)) return false;
33818               var nodesToSearch = [];
33819
33820               while (node) {
33821                 for (var i = 0; i < node.children.length; i++) {
33822                   var child = node.children[i];
33823                   var childBBox = node.leaf ? this.toBBox(child) : child;
33824
33825                   if (intersects(bbox, childBBox)) {
33826                     if (node.leaf || contains(bbox, childBBox)) return true;
33827                     nodesToSearch.push(child);
33828                   }
33829                 }
33830
33831                 node = nodesToSearch.pop();
33832               }
33833
33834               return false;
33835             }
33836           }, {
33837             key: "load",
33838             value: function load(data) {
33839               if (!(data && data.length)) return this;
33840
33841               if (data.length < this._minEntries) {
33842                 for (var i = 0; i < data.length; i++) {
33843                   this.insert(data[i]);
33844                 }
33845
33846                 return this;
33847               } // recursively build the tree with the given data from scratch using OMT algorithm
33848
33849
33850               var node = this._build(data.slice(), 0, data.length - 1, 0);
33851
33852               if (!this.data.children.length) {
33853                 // save as is if tree is empty
33854                 this.data = node;
33855               } else if (this.data.height === node.height) {
33856                 // split root if trees have the same height
33857                 this._splitRoot(this.data, node);
33858               } else {
33859                 if (this.data.height < node.height) {
33860                   // swap trees if inserted one is bigger
33861                   var tmpNode = this.data;
33862                   this.data = node;
33863                   node = tmpNode;
33864                 } // insert the small tree into the large tree at appropriate level
33865
33866
33867                 this._insert(node, this.data.height - node.height - 1, true);
33868               }
33869
33870               return this;
33871             }
33872           }, {
33873             key: "insert",
33874             value: function insert(item) {
33875               if (item) this._insert(item, this.data.height - 1);
33876               return this;
33877             }
33878           }, {
33879             key: "clear",
33880             value: function clear() {
33881               this.data = createNode([]);
33882               return this;
33883             }
33884           }, {
33885             key: "remove",
33886             value: function remove(item, equalsFn) {
33887               if (!item) return this;
33888               var node = this.data;
33889               var bbox = this.toBBox(item);
33890               var path = [];
33891               var indexes = [];
33892               var i, parent, goingUp; // depth-first iterative tree traversal
33893
33894               while (node || path.length) {
33895                 if (!node) {
33896                   // go up
33897                   node = path.pop();
33898                   parent = path[path.length - 1];
33899                   i = indexes.pop();
33900                   goingUp = true;
33901                 }
33902
33903                 if (node.leaf) {
33904                   // check current node
33905                   var index = findItem(item, node.children, equalsFn);
33906
33907                   if (index !== -1) {
33908                     // item found, remove the item and condense tree upwards
33909                     node.children.splice(index, 1);
33910                     path.push(node);
33911
33912                     this._condense(path);
33913
33914                     return this;
33915                   }
33916                 }
33917
33918                 if (!goingUp && !node.leaf && contains(node, bbox)) {
33919                   // go down
33920                   path.push(node);
33921                   indexes.push(i);
33922                   i = 0;
33923                   parent = node;
33924                   node = node.children[0];
33925                 } else if (parent) {
33926                   // go right
33927                   i++;
33928                   node = parent.children[i];
33929                   goingUp = false;
33930                 } else node = null; // nothing found
33931
33932               }
33933
33934               return this;
33935             }
33936           }, {
33937             key: "toBBox",
33938             value: function toBBox(item) {
33939               return item;
33940             }
33941           }, {
33942             key: "compareMinX",
33943             value: function compareMinX(a, b) {
33944               return a.minX - b.minX;
33945             }
33946           }, {
33947             key: "compareMinY",
33948             value: function compareMinY(a, b) {
33949               return a.minY - b.minY;
33950             }
33951           }, {
33952             key: "toJSON",
33953             value: function toJSON() {
33954               return this.data;
33955             }
33956           }, {
33957             key: "fromJSON",
33958             value: function fromJSON(data) {
33959               this.data = data;
33960               return this;
33961             }
33962           }, {
33963             key: "_all",
33964             value: function _all(node, result) {
33965               var nodesToSearch = [];
33966
33967               while (node) {
33968                 if (node.leaf) result.push.apply(result, _toConsumableArray(node.children));else nodesToSearch.push.apply(nodesToSearch, _toConsumableArray(node.children));
33969                 node = nodesToSearch.pop();
33970               }
33971
33972               return result;
33973             }
33974           }, {
33975             key: "_build",
33976             value: function _build(items, left, right, height) {
33977               var N = right - left + 1;
33978               var M = this._maxEntries;
33979               var node;
33980
33981               if (N <= M) {
33982                 // reached leaf level; return leaf
33983                 node = createNode(items.slice(left, right + 1));
33984                 calcBBox(node, this.toBBox);
33985                 return node;
33986               }
33987
33988               if (!height) {
33989                 // target height of the bulk-loaded tree
33990                 height = Math.ceil(Math.log(N) / Math.log(M)); // target number of root entries to maximize storage utilization
33991
33992                 M = Math.ceil(N / Math.pow(M, height - 1));
33993               }
33994
33995               node = createNode([]);
33996               node.leaf = false;
33997               node.height = height; // split the items into M mostly square tiles
33998
33999               var N2 = Math.ceil(N / M);
34000               var N1 = N2 * Math.ceil(Math.sqrt(M));
34001               multiSelect(items, left, right, N1, this.compareMinX);
34002
34003               for (var i = left; i <= right; i += N1) {
34004                 var right2 = Math.min(i + N1 - 1, right);
34005                 multiSelect(items, i, right2, N2, this.compareMinY);
34006
34007                 for (var j = i; j <= right2; j += N2) {
34008                   var right3 = Math.min(j + N2 - 1, right2); // pack each entry recursively
34009
34010                   node.children.push(this._build(items, j, right3, height - 1));
34011                 }
34012               }
34013
34014               calcBBox(node, this.toBBox);
34015               return node;
34016             }
34017           }, {
34018             key: "_chooseSubtree",
34019             value: function _chooseSubtree(bbox, node, level, path) {
34020               while (true) {
34021                 path.push(node);
34022                 if (node.leaf || path.length - 1 === level) break;
34023                 var minArea = Infinity;
34024                 var minEnlargement = Infinity;
34025                 var targetNode = void 0;
34026
34027                 for (var i = 0; i < node.children.length; i++) {
34028                   var child = node.children[i];
34029                   var area = bboxArea(child);
34030                   var enlargement = enlargedArea(bbox, child) - area; // choose entry with the least area enlargement
34031
34032                   if (enlargement < minEnlargement) {
34033                     minEnlargement = enlargement;
34034                     minArea = area < minArea ? area : minArea;
34035                     targetNode = child;
34036                   } else if (enlargement === minEnlargement) {
34037                     // otherwise choose one with the smallest area
34038                     if (area < minArea) {
34039                       minArea = area;
34040                       targetNode = child;
34041                     }
34042                   }
34043                 }
34044
34045                 node = targetNode || node.children[0];
34046               }
34047
34048               return node;
34049             }
34050           }, {
34051             key: "_insert",
34052             value: function _insert(item, level, isNode) {
34053               var bbox = isNode ? item : this.toBBox(item);
34054               var insertPath = []; // find the best node for accommodating the item, saving all nodes along the path too
34055
34056               var node = this._chooseSubtree(bbox, this.data, level, insertPath); // put the item into the node
34057
34058
34059               node.children.push(item);
34060               extend$1(node, bbox); // split on node overflow; propagate upwards if necessary
34061
34062               while (level >= 0) {
34063                 if (insertPath[level].children.length > this._maxEntries) {
34064                   this._split(insertPath, level);
34065
34066                   level--;
34067                 } else break;
34068               } // adjust bboxes along the insertion path
34069
34070
34071               this._adjustParentBBoxes(bbox, insertPath, level);
34072             } // split overflowed node into two
34073
34074           }, {
34075             key: "_split",
34076             value: function _split(insertPath, level) {
34077               var node = insertPath[level];
34078               var M = node.children.length;
34079               var m = this._minEntries;
34080
34081               this._chooseSplitAxis(node, m, M);
34082
34083               var splitIndex = this._chooseSplitIndex(node, m, M);
34084
34085               var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
34086               newNode.height = node.height;
34087               newNode.leaf = node.leaf;
34088               calcBBox(node, this.toBBox);
34089               calcBBox(newNode, this.toBBox);
34090               if (level) insertPath[level - 1].children.push(newNode);else this._splitRoot(node, newNode);
34091             }
34092           }, {
34093             key: "_splitRoot",
34094             value: function _splitRoot(node, newNode) {
34095               // split root node
34096               this.data = createNode([node, newNode]);
34097               this.data.height = node.height + 1;
34098               this.data.leaf = false;
34099               calcBBox(this.data, this.toBBox);
34100             }
34101           }, {
34102             key: "_chooseSplitIndex",
34103             value: function _chooseSplitIndex(node, m, M) {
34104               var index;
34105               var minOverlap = Infinity;
34106               var minArea = Infinity;
34107
34108               for (var i = m; i <= M - m; i++) {
34109                 var bbox1 = distBBox(node, 0, i, this.toBBox);
34110                 var bbox2 = distBBox(node, i, M, this.toBBox);
34111                 var overlap = intersectionArea(bbox1, bbox2);
34112                 var area = bboxArea(bbox1) + bboxArea(bbox2); // choose distribution with minimum overlap
34113
34114                 if (overlap < minOverlap) {
34115                   minOverlap = overlap;
34116                   index = i;
34117                   minArea = area < minArea ? area : minArea;
34118                 } else if (overlap === minOverlap) {
34119                   // otherwise choose distribution with minimum area
34120                   if (area < minArea) {
34121                     minArea = area;
34122                     index = i;
34123                   }
34124                 }
34125               }
34126
34127               return index || M - m;
34128             } // sorts node children by the best axis for split
34129
34130           }, {
34131             key: "_chooseSplitAxis",
34132             value: function _chooseSplitAxis(node, m, M) {
34133               var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX;
34134               var compareMinY = node.leaf ? this.compareMinY : compareNodeMinY;
34135
34136               var xMargin = this._allDistMargin(node, m, M, compareMinX);
34137
34138               var yMargin = this._allDistMargin(node, m, M, compareMinY); // if total distributions margin value is minimal for x, sort by minX,
34139               // otherwise it's already sorted by minY
34140
34141
34142               if (xMargin < yMargin) node.children.sort(compareMinX);
34143             } // total margin of all possible split distributions where each node is at least m full
34144
34145           }, {
34146             key: "_allDistMargin",
34147             value: function _allDistMargin(node, m, M, compare) {
34148               node.children.sort(compare);
34149               var toBBox = this.toBBox;
34150               var leftBBox = distBBox(node, 0, m, toBBox);
34151               var rightBBox = distBBox(node, M - m, M, toBBox);
34152               var margin = bboxMargin(leftBBox) + bboxMargin(rightBBox);
34153
34154               for (var i = m; i < M - m; i++) {
34155                 var child = node.children[i];
34156                 extend$1(leftBBox, node.leaf ? toBBox(child) : child);
34157                 margin += bboxMargin(leftBBox);
34158               }
34159
34160               for (var _i = M - m - 1; _i >= m; _i--) {
34161                 var _child = node.children[_i];
34162                 extend$1(rightBBox, node.leaf ? toBBox(_child) : _child);
34163                 margin += bboxMargin(rightBBox);
34164               }
34165
34166               return margin;
34167             }
34168           }, {
34169             key: "_adjustParentBBoxes",
34170             value: function _adjustParentBBoxes(bbox, path, level) {
34171               // adjust bboxes along the given tree path
34172               for (var i = level; i >= 0; i--) {
34173                 extend$1(path[i], bbox);
34174               }
34175             }
34176           }, {
34177             key: "_condense",
34178             value: function _condense(path) {
34179               // go through the path, removing empty nodes and updating bboxes
34180               for (var i = path.length - 1, siblings; i >= 0; i--) {
34181                 if (path[i].children.length === 0) {
34182                   if (i > 0) {
34183                     siblings = path[i - 1].children;
34184                     siblings.splice(siblings.indexOf(path[i]), 1);
34185                   } else this.clear();
34186                 } else calcBBox(path[i], this.toBBox);
34187               }
34188             }
34189           }]);
34190
34191           return RBush;
34192         }();
34193
34194         function findItem(item, items, equalsFn) {
34195           if (!equalsFn) return items.indexOf(item);
34196
34197           for (var i = 0; i < items.length; i++) {
34198             if (equalsFn(item, items[i])) return i;
34199           }
34200
34201           return -1;
34202         } // calculate node's bbox from bboxes of its children
34203
34204
34205         function calcBBox(node, toBBox) {
34206           distBBox(node, 0, node.children.length, toBBox, node);
34207         } // min bounding rectangle of node children from k to p-1
34208
34209
34210         function distBBox(node, k, p, toBBox, destNode) {
34211           if (!destNode) destNode = createNode(null);
34212           destNode.minX = Infinity;
34213           destNode.minY = Infinity;
34214           destNode.maxX = -Infinity;
34215           destNode.maxY = -Infinity;
34216
34217           for (var i = k; i < p; i++) {
34218             var child = node.children[i];
34219             extend$1(destNode, node.leaf ? toBBox(child) : child);
34220           }
34221
34222           return destNode;
34223         }
34224
34225         function extend$1(a, b) {
34226           a.minX = Math.min(a.minX, b.minX);
34227           a.minY = Math.min(a.minY, b.minY);
34228           a.maxX = Math.max(a.maxX, b.maxX);
34229           a.maxY = Math.max(a.maxY, b.maxY);
34230           return a;
34231         }
34232
34233         function compareNodeMinX(a, b) {
34234           return a.minX - b.minX;
34235         }
34236
34237         function compareNodeMinY(a, b) {
34238           return a.minY - b.minY;
34239         }
34240
34241         function bboxArea(a) {
34242           return (a.maxX - a.minX) * (a.maxY - a.minY);
34243         }
34244
34245         function bboxMargin(a) {
34246           return a.maxX - a.minX + (a.maxY - a.minY);
34247         }
34248
34249         function enlargedArea(a, b) {
34250           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));
34251         }
34252
34253         function intersectionArea(a, b) {
34254           var minX = Math.max(a.minX, b.minX);
34255           var minY = Math.max(a.minY, b.minY);
34256           var maxX = Math.min(a.maxX, b.maxX);
34257           var maxY = Math.min(a.maxY, b.maxY);
34258           return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
34259         }
34260
34261         function contains(a, b) {
34262           return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
34263         }
34264
34265         function intersects(a, b) {
34266           return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
34267         }
34268
34269         function createNode(children) {
34270           return {
34271             children: children,
34272             height: 1,
34273             leaf: true,
34274             minX: Infinity,
34275             minY: Infinity,
34276             maxX: -Infinity,
34277             maxY: -Infinity
34278           };
34279         } // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
34280         // combines selection algorithm with binary divide & conquer approach
34281
34282
34283         function multiSelect(arr, left, right, n, compare) {
34284           var stack = [left, right];
34285
34286           while (stack.length) {
34287             right = stack.pop();
34288             left = stack.pop();
34289             if (right - left <= n) continue;
34290             var mid = left + Math.ceil((right - left) / n / 2) * n;
34291             quickselect$1(arr, mid, left, right, compare);
34292             stack.push(left, mid, mid, right);
34293           }
34294         }
34295
34296         var tiler = utilTiler();
34297         var dispatch$1 = dispatch('loaded');
34298         var _tileZoom = 14;
34299         var _krUrlRoot = 'https://www.keepright.at';
34300         var _krData = {
34301           errorTypes: {},
34302           localizeStrings: {}
34303         }; // This gets reassigned if reset
34304
34305         var _cache;
34306
34307         var _krRuleset = [// no 20 - multiple node on same spot - these are mostly boundaries overlapping roads
34308         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];
34309
34310         function abortRequest(controller) {
34311           if (controller) {
34312             controller.abort();
34313           }
34314         }
34315
34316         function abortUnwantedRequests(cache, tiles) {
34317           Object.keys(cache.inflightTile).forEach(function (k) {
34318             var wanted = tiles.find(function (tile) {
34319               return k === tile.id;
34320             });
34321
34322             if (!wanted) {
34323               abortRequest(cache.inflightTile[k]);
34324               delete cache.inflightTile[k];
34325             }
34326           });
34327         }
34328
34329         function encodeIssueRtree(d) {
34330           return {
34331             minX: d.loc[0],
34332             minY: d.loc[1],
34333             maxX: d.loc[0],
34334             maxY: d.loc[1],
34335             data: d
34336           };
34337         } // Replace or remove QAItem from rtree
34338
34339
34340         function updateRtree(item, replace) {
34341           _cache.rtree.remove(item, function (a, b) {
34342             return a.data.id === b.data.id;
34343           });
34344
34345           if (replace) {
34346             _cache.rtree.insert(item);
34347           }
34348         }
34349
34350         function tokenReplacements(d) {
34351           if (!(d instanceof QAItem)) return;
34352           var htmlRegex = new RegExp(/<\/[a-z][\s\S]*>/);
34353           var replacements = {};
34354           var issueTemplate = _krData.errorTypes[d.whichType];
34355
34356           if (!issueTemplate) {
34357             /* eslint-disable no-console */
34358             console.log('No Template: ', d.whichType);
34359             console.log('  ', d.description);
34360             /* eslint-enable no-console */
34361
34362             return;
34363           } // some descriptions are just fixed text
34364
34365
34366           if (!issueTemplate.regex) return; // regex pattern should match description with variable details captured
34367
34368           var errorRegex = new RegExp(issueTemplate.regex, 'i');
34369           var errorMatch = errorRegex.exec(d.description);
34370
34371           if (!errorMatch) {
34372             /* eslint-disable no-console */
34373             console.log('Unmatched: ', d.whichType);
34374             console.log('  ', d.description);
34375             console.log('  ', errorRegex);
34376             /* eslint-enable no-console */
34377
34378             return;
34379           }
34380
34381           for (var i = 1; i < errorMatch.length; i++) {
34382             // skip first
34383             var capture = errorMatch[i];
34384             var idType = void 0;
34385             idType = 'IDs' in issueTemplate ? issueTemplate.IDs[i - 1] : '';
34386
34387             if (idType && capture) {
34388               // link IDs if present in the capture
34389               capture = parseError(capture, idType);
34390             } else if (htmlRegex.test(capture)) {
34391               // escape any html in non-IDs
34392               capture = '\\' + capture + '\\';
34393             } else {
34394               var compare = capture.toLowerCase();
34395
34396               if (_krData.localizeStrings[compare]) {
34397                 // some replacement strings can be localized
34398                 capture = _t('QA.keepRight.error_parts.' + _krData.localizeStrings[compare]);
34399               }
34400             }
34401
34402             replacements['var' + i] = capture;
34403           }
34404
34405           return replacements;
34406         }
34407
34408         function parseError(capture, idType) {
34409           var compare = capture.toLowerCase();
34410
34411           if (_krData.localizeStrings[compare]) {
34412             // some replacement strings can be localized
34413             capture = _t('QA.keepRight.error_parts.' + _krData.localizeStrings[compare]);
34414           }
34415
34416           switch (idType) {
34417             // link a string like "this node"
34418             case 'this':
34419               capture = linkErrorObject(capture);
34420               break;
34421
34422             case 'url':
34423               capture = linkURL(capture);
34424               break;
34425             // link an entity ID
34426
34427             case 'n':
34428             case 'w':
34429             case 'r':
34430               capture = linkEntity(idType + capture);
34431               break;
34432             // some errors have more complex ID lists/variance
34433
34434             case '20':
34435               capture = parse20(capture);
34436               break;
34437
34438             case '211':
34439               capture = parse211(capture);
34440               break;
34441
34442             case '231':
34443               capture = parse231(capture);
34444               break;
34445
34446             case '294':
34447               capture = parse294(capture);
34448               break;
34449
34450             case '370':
34451               capture = parse370(capture);
34452               break;
34453           }
34454
34455           return capture;
34456
34457           function linkErrorObject(d) {
34458             return "<a class=\"error_object_link\">".concat(d, "</a>");
34459           }
34460
34461           function linkEntity(d) {
34462             return "<a class=\"error_entity_link\">".concat(d, "</a>");
34463           }
34464
34465           function linkURL(d) {
34466             return "<a class=\"kr_external_link\" target=\"_blank\" href=\"".concat(d, "\">").concat(d, "</a>");
34467           } // arbitrary node list of form: #ID, #ID, #ID...
34468
34469
34470           function parse211(capture) {
34471             var newList = [];
34472             var items = capture.split(', ');
34473             items.forEach(function (item) {
34474               // ID has # at the front
34475               var id = linkEntity('n' + item.slice(1));
34476               newList.push(id);
34477             });
34478             return newList.join(', ');
34479           } // arbitrary way list of form: #ID(layer),#ID(layer),#ID(layer)...
34480
34481
34482           function parse231(capture) {
34483             var newList = []; // unfortunately 'layer' can itself contain commas, so we split on '),'
34484
34485             var items = capture.split('),');
34486             items.forEach(function (item) {
34487               var match = item.match(/\#(\d+)\((.+)\)?/);
34488
34489               if (match !== null && match.length > 2) {
34490                 newList.push(linkEntity('w' + match[1]) + ' ' + _t('QA.keepRight.errorTypes.231.layer', {
34491                   layer: match[2]
34492                 }));
34493               }
34494             });
34495             return newList.join(', ');
34496           } // arbitrary node/relation list of form: from node #ID,to relation #ID,to node #ID...
34497
34498
34499           function parse294(capture) {
34500             var newList = [];
34501             var items = capture.split(',');
34502             items.forEach(function (item) {
34503               // item of form "from/to node/relation #ID"
34504               item = item.split(' '); // to/from role is more clear in quotes
34505
34506               var role = "\"".concat(item[0], "\""); // first letter of node/relation provides the type
34507
34508               var idType = item[1].slice(0, 1); // ID has # at the front
34509
34510               var id = item[2].slice(1);
34511               id = linkEntity(idType + id);
34512               newList.push("".concat(role, " ").concat(item[1], " ").concat(id));
34513             });
34514             return newList.join(', ');
34515           } // may or may not include the string "(including the name 'name')"
34516
34517
34518           function parse370(capture) {
34519             if (!capture) return '';
34520             var match = capture.match(/\(including the name (\'.+\')\)/);
34521
34522             if (match && match.length) {
34523               return _t('QA.keepRight.errorTypes.370.including_the_name', {
34524                 name: match[1]
34525               });
34526             }
34527
34528             return '';
34529           } // arbitrary node list of form: #ID,#ID,#ID...
34530
34531
34532           function parse20(capture) {
34533             var newList = [];
34534             var items = capture.split(',');
34535             items.forEach(function (item) {
34536               // ID has # at the front
34537               var id = linkEntity('n' + item.slice(1));
34538               newList.push(id);
34539             });
34540             return newList.join(', ');
34541           }
34542         }
34543
34544         var serviceKeepRight = {
34545           title: 'keepRight',
34546           init: function init() {
34547             _mainFileFetcher.get('keepRight').then(function (d) {
34548               return _krData = d;
34549             });
34550
34551             if (!_cache) {
34552               this.reset();
34553             }
34554
34555             this.event = utilRebind(this, dispatch$1, 'on');
34556           },
34557           reset: function reset() {
34558             if (_cache) {
34559               Object.values(_cache.inflightTile).forEach(abortRequest);
34560             }
34561
34562             _cache = {
34563               data: {},
34564               loadedTile: {},
34565               inflightTile: {},
34566               inflightPost: {},
34567               closed: {},
34568               rtree: new RBush()
34569             };
34570           },
34571           // KeepRight API:  http://osm.mueschelsoft.de/keepright/interfacing.php
34572           loadIssues: function loadIssues(projection) {
34573             var _this = this;
34574
34575             var options = {
34576               format: 'geojson',
34577               ch: _krRuleset
34578             }; // determine the needed tiles to cover the view
34579
34580             var tiles = tiler.zoomExtent([_tileZoom, _tileZoom]).getTiles(projection); // abort inflight requests that are no longer needed
34581
34582             abortUnwantedRequests(_cache, tiles); // issue new requests..
34583
34584             tiles.forEach(function (tile) {
34585               if (_cache.loadedTile[tile.id] || _cache.inflightTile[tile.id]) return;
34586
34587               var _tile$extent$rectangl = tile.extent.rectangle(),
34588                   _tile$extent$rectangl2 = _slicedToArray(_tile$extent$rectangl, 4),
34589                   left = _tile$extent$rectangl2[0],
34590                   top = _tile$extent$rectangl2[1],
34591                   right = _tile$extent$rectangl2[2],
34592                   bottom = _tile$extent$rectangl2[3];
34593
34594               var params = Object.assign({}, options, {
34595                 left: left,
34596                 bottom: bottom,
34597                 right: right,
34598                 top: top
34599               });
34600               var url = "".concat(_krUrlRoot, "/export.php?") + utilQsString(params);
34601               var controller = new AbortController();
34602               _cache.inflightTile[tile.id] = controller;
34603               d3_json(url, {
34604                 signal: controller.signal
34605               }).then(function (data) {
34606                 delete _cache.inflightTile[tile.id];
34607                 _cache.loadedTile[tile.id] = true;
34608
34609                 if (!data || !data.features || !data.features.length) {
34610                   throw new Error('No Data');
34611                 }
34612
34613                 data.features.forEach(function (feature) {
34614                   var _feature$properties = feature.properties,
34615                       itemType = _feature$properties.error_type,
34616                       id = _feature$properties.error_id,
34617                       _feature$properties$c = _feature$properties.comment,
34618                       comment = _feature$properties$c === void 0 ? null : _feature$properties$c,
34619                       objectId = _feature$properties.object_id,
34620                       objectType = _feature$properties.object_type,
34621                       schema = _feature$properties.schema,
34622                       title = _feature$properties.title;
34623                   var loc = feature.geometry.coordinates,
34624                       _feature$properties$d = feature.properties.description,
34625                       description = _feature$properties$d === void 0 ? '' : _feature$properties$d; // if there is a parent, save its error type e.g.:
34626                   //  Error 191 = "highway-highway"
34627                   //  Error 190 = "intersections without junctions"  (parent)
34628
34629                   var issueTemplate = _krData.errorTypes[itemType];
34630                   var parentIssueType = (Math.floor(itemType / 10) * 10).toString(); // try to handle error type directly, fallback to parent error type.
34631
34632                   var whichType = issueTemplate ? itemType : parentIssueType;
34633                   var whichTemplate = _krData.errorTypes[whichType]; // Rewrite a few of the errors at this point..
34634                   // This is done to make them easier to linkify and translate.
34635
34636                   switch (whichType) {
34637                     case '170':
34638                       description = "This feature has a FIXME tag: ".concat(description);
34639                       break;
34640
34641                     case '292':
34642                     case '293':
34643                       description = description.replace('A turn-', 'This turn-');
34644                       break;
34645
34646                     case '294':
34647                     case '295':
34648                     case '296':
34649                     case '297':
34650                     case '298':
34651                       description = "This turn-restriction~".concat(description);
34652                       break;
34653
34654                     case '300':
34655                       description = 'This highway is missing a maxspeed tag';
34656                       break;
34657
34658                     case '411':
34659                     case '412':
34660                     case '413':
34661                       description = "This feature~".concat(description);
34662                       break;
34663                   } // move markers slightly so it doesn't obscure the geometry,
34664                   // then move markers away from other coincident markers
34665
34666
34667                   var coincident = false;
34668
34669                   do {
34670                     // first time, move marker up. after that, move marker right.
34671                     var delta = coincident ? [0.00001, 0] : [0, 0.00001];
34672                     loc = geoVecAdd(loc, delta);
34673                     var bbox = geoExtent(loc).bbox();
34674                     coincident = _cache.rtree.search(bbox).length;
34675                   } while (coincident);
34676
34677                   var d = new QAItem(loc, _this, itemType, id, {
34678                     comment: comment,
34679                     description: description,
34680                     whichType: whichType,
34681                     parentIssueType: parentIssueType,
34682                     severity: whichTemplate.severity || 'error',
34683                     objectId: objectId,
34684                     objectType: objectType,
34685                     schema: schema,
34686                     title: title
34687                   });
34688                   d.replacements = tokenReplacements(d);
34689                   _cache.data[id] = d;
34690
34691                   _cache.rtree.insert(encodeIssueRtree(d));
34692                 });
34693                 dispatch$1.call('loaded');
34694               })["catch"](function () {
34695                 delete _cache.inflightTile[tile.id];
34696                 _cache.loadedTile[tile.id] = true;
34697               });
34698             });
34699           },
34700           postUpdate: function postUpdate(d, callback) {
34701             var _this2 = this;
34702
34703             if (_cache.inflightPost[d.id]) {
34704               return callback({
34705                 message: 'Error update already inflight',
34706                 status: -2
34707               }, d);
34708             }
34709
34710             var params = {
34711               schema: d.schema,
34712               id: d.id
34713             };
34714
34715             if (d.newStatus) {
34716               params.st = d.newStatus;
34717             }
34718
34719             if (d.newComment !== undefined) {
34720               params.co = d.newComment;
34721             } // NOTE: This throws a CORS err, but it seems successful.
34722             // We don't care too much about the response, so this is fine.
34723
34724
34725             var url = "".concat(_krUrlRoot, "/comment.php?") + utilQsString(params);
34726             var controller = new AbortController();
34727             _cache.inflightPost[d.id] = controller; // Since this is expected to throw an error just continue as if it worked
34728             // (worst case scenario the request truly fails and issue will show up if iD restarts)
34729
34730             d3_json(url, {
34731               signal: controller.signal
34732             })["finally"](function () {
34733               delete _cache.inflightPost[d.id];
34734
34735               if (d.newStatus === 'ignore') {
34736                 // ignore permanently (false positive)
34737                 _this2.removeItem(d);
34738               } else if (d.newStatus === 'ignore_t') {
34739                 // ignore temporarily (error fixed)
34740                 _this2.removeItem(d);
34741
34742                 _cache.closed["".concat(d.schema, ":").concat(d.id)] = true;
34743               } else {
34744                 d = _this2.replaceItem(d.update({
34745                   comment: d.newComment,
34746                   newComment: undefined,
34747                   newState: undefined
34748                 }));
34749               }
34750
34751               if (callback) callback(null, d);
34752             });
34753           },
34754           // Get all cached QAItems covering the viewport
34755           getItems: function getItems(projection) {
34756             var viewport = projection.clipExtent();
34757             var min = [viewport[0][0], viewport[1][1]];
34758             var max = [viewport[1][0], viewport[0][1]];
34759             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
34760             return _cache.rtree.search(bbox).map(function (d) {
34761               return d.data;
34762             });
34763           },
34764           // Get a QAItem from cache
34765           // NOTE: Don't change method name until UI v3 is merged
34766           getError: function getError(id) {
34767             return _cache.data[id];
34768           },
34769           // Replace a single QAItem in the cache
34770           replaceItem: function replaceItem(item) {
34771             if (!(item instanceof QAItem) || !item.id) return;
34772             _cache.data[item.id] = item;
34773             updateRtree(encodeIssueRtree(item), true); // true = replace
34774
34775             return item;
34776           },
34777           // Remove a single QAItem from the cache
34778           removeItem: function removeItem(item) {
34779             if (!(item instanceof QAItem) || !item.id) return;
34780             delete _cache.data[item.id];
34781             updateRtree(encodeIssueRtree(item), false); // false = remove
34782           },
34783           issueURL: function issueURL(item) {
34784             return "".concat(_krUrlRoot, "/report_map.php?schema=").concat(item.schema, "&error=").concat(item.id);
34785           },
34786           // Get an array of issues closed during this session.
34787           // Used to populate `closed:keepright` changeset tag
34788           getClosedIDs: function getClosedIDs() {
34789             return Object.keys(_cache.closed).sort();
34790           }
34791         };
34792
34793         var tiler$1 = utilTiler();
34794         var dispatch$2 = dispatch('loaded');
34795         var _tileZoom$1 = 14;
34796         var _impOsmUrls = {
34797           ow: 'https://grab.community.improve-osm.org/directionOfFlowService',
34798           mr: 'https://grab.community.improve-osm.org/missingGeoService',
34799           tr: 'https://grab.community.improve-osm.org/turnRestrictionService'
34800         };
34801         var _impOsmData = {
34802           icons: {}
34803         }; // This gets reassigned if reset
34804
34805         var _cache$1;
34806
34807         function abortRequest$1(i) {
34808           Object.values(i).forEach(function (controller) {
34809             if (controller) {
34810               controller.abort();
34811             }
34812           });
34813         }
34814
34815         function abortUnwantedRequests$1(cache, tiles) {
34816           Object.keys(cache.inflightTile).forEach(function (k) {
34817             var wanted = tiles.find(function (tile) {
34818               return k === tile.id;
34819             });
34820
34821             if (!wanted) {
34822               abortRequest$1(cache.inflightTile[k]);
34823               delete cache.inflightTile[k];
34824             }
34825           });
34826         }
34827
34828         function encodeIssueRtree$1(d) {
34829           return {
34830             minX: d.loc[0],
34831             minY: d.loc[1],
34832             maxX: d.loc[0],
34833             maxY: d.loc[1],
34834             data: d
34835           };
34836         } // Replace or remove QAItem from rtree
34837
34838
34839         function updateRtree$1(item, replace) {
34840           _cache$1.rtree.remove(item, function (a, b) {
34841             return a.data.id === b.data.id;
34842           });
34843
34844           if (replace) {
34845             _cache$1.rtree.insert(item);
34846           }
34847         }
34848
34849         function linkErrorObject(d) {
34850           return "<a class=\"error_object_link\">".concat(d, "</a>");
34851         }
34852
34853         function linkEntity(d) {
34854           return "<a class=\"error_entity_link\">".concat(d, "</a>");
34855         }
34856
34857         function pointAverage(points) {
34858           if (points.length) {
34859             var sum = points.reduce(function (acc, point) {
34860               return geoVecAdd(acc, [point.lon, point.lat]);
34861             }, [0, 0]);
34862             return geoVecScale(sum, 1 / points.length);
34863           } else {
34864             return [0, 0];
34865           }
34866         }
34867
34868         function relativeBearing(p1, p2) {
34869           var angle = Math.atan2(p2.lon - p1.lon, p2.lat - p1.lat);
34870
34871           if (angle < 0) {
34872             angle += 2 * Math.PI;
34873           } // Return degrees
34874
34875
34876           return angle * 180 / Math.PI;
34877         } // Assuming range [0,360)
34878
34879
34880         function cardinalDirection(bearing) {
34881           var dir = 45 * Math.round(bearing / 45);
34882           var compass = {
34883             0: 'north',
34884             45: 'northeast',
34885             90: 'east',
34886             135: 'southeast',
34887             180: 'south',
34888             225: 'southwest',
34889             270: 'west',
34890             315: 'northwest',
34891             360: 'north'
34892           };
34893           return _t("QA.improveOSM.directions.".concat(compass[dir]));
34894         } // Errors shouldn't obscure each other
34895
34896
34897         function preventCoincident(loc, bumpUp) {
34898           var coincident = false;
34899
34900           do {
34901             // first time, move marker up. after that, move marker right.
34902             var delta = coincident ? [0.00001, 0] : bumpUp ? [0, 0.00001] : [0, 0];
34903             loc = geoVecAdd(loc, delta);
34904             var bbox = geoExtent(loc).bbox();
34905             coincident = _cache$1.rtree.search(bbox).length;
34906           } while (coincident);
34907
34908           return loc;
34909         }
34910
34911         var serviceImproveOSM = {
34912           title: 'improveOSM',
34913           init: function init() {
34914             _mainFileFetcher.get('qa_data').then(function (d) {
34915               return _impOsmData = d.improveOSM;
34916             });
34917
34918             if (!_cache$1) {
34919               this.reset();
34920             }
34921
34922             this.event = utilRebind(this, dispatch$2, 'on');
34923           },
34924           reset: function reset() {
34925             if (_cache$1) {
34926               Object.values(_cache$1.inflightTile).forEach(abortRequest$1);
34927             }
34928
34929             _cache$1 = {
34930               data: {},
34931               loadedTile: {},
34932               inflightTile: {},
34933               inflightPost: {},
34934               closed: {},
34935               rtree: new RBush()
34936             };
34937           },
34938           loadIssues: function loadIssues(projection) {
34939             var _this = this;
34940
34941             var options = {
34942               client: 'iD',
34943               status: 'OPEN',
34944               zoom: '19' // Use a high zoom so that clusters aren't returned
34945
34946             }; // determine the needed tiles to cover the view
34947
34948             var tiles = tiler$1.zoomExtent([_tileZoom$1, _tileZoom$1]).getTiles(projection); // abort inflight requests that are no longer needed
34949
34950             abortUnwantedRequests$1(_cache$1, tiles); // issue new requests..
34951
34952             tiles.forEach(function (tile) {
34953               if (_cache$1.loadedTile[tile.id] || _cache$1.inflightTile[tile.id]) return;
34954
34955               var _tile$extent$rectangl = tile.extent.rectangle(),
34956                   _tile$extent$rectangl2 = _slicedToArray(_tile$extent$rectangl, 4),
34957                   east = _tile$extent$rectangl2[0],
34958                   north = _tile$extent$rectangl2[1],
34959                   west = _tile$extent$rectangl2[2],
34960                   south = _tile$extent$rectangl2[3];
34961
34962               var params = Object.assign({}, options, {
34963                 east: east,
34964                 south: south,
34965                 west: west,
34966                 north: north
34967               }); // 3 separate requests to store for each tile
34968
34969               var requests = {};
34970               Object.keys(_impOsmUrls).forEach(function (k) {
34971                 // We exclude WATER from missing geometry as it doesn't seem useful
34972                 // We use most confident one-way and turn restrictions only, still have false positives
34973                 var kParams = Object.assign({}, params, k === 'mr' ? {
34974                   type: 'PARKING,ROAD,BOTH,PATH'
34975                 } : {
34976                   confidenceLevel: 'C1'
34977                 });
34978                 var url = "".concat(_impOsmUrls[k], "/search?") + utilQsString(kParams);
34979                 var controller = new AbortController();
34980                 requests[k] = controller;
34981                 d3_json(url, {
34982                   signal: controller.signal
34983                 }).then(function (data) {
34984                   delete _cache$1.inflightTile[tile.id][k];
34985
34986                   if (!Object.keys(_cache$1.inflightTile[tile.id]).length) {
34987                     delete _cache$1.inflightTile[tile.id];
34988                     _cache$1.loadedTile[tile.id] = true;
34989                   } // Road segments at high zoom == oneways
34990
34991
34992                   if (data.roadSegments) {
34993                     data.roadSegments.forEach(function (feature) {
34994                       // Position error at the approximate middle of the segment
34995                       var points = feature.points,
34996                           wayId = feature.wayId,
34997                           fromNodeId = feature.fromNodeId,
34998                           toNodeId = feature.toNodeId;
34999                       var itemId = "".concat(wayId).concat(fromNodeId).concat(toNodeId);
35000                       var mid = points.length / 2;
35001                       var loc; // Even number of points, find midpoint of the middle two
35002                       // Odd number of points, use position of very middle point
35003
35004                       if (mid % 1 === 0) {
35005                         loc = pointAverage([points[mid - 1], points[mid]]);
35006                       } else {
35007                         mid = points[Math.floor(mid)];
35008                         loc = [mid.lon, mid.lat];
35009                       } // One-ways can land on same segment in opposite direction
35010
35011
35012                       loc = preventCoincident(loc, false);
35013                       var d = new QAItem(loc, _this, k, itemId, {
35014                         issueKey: k,
35015                         // used as a category
35016                         identifier: {
35017                           // used to post changes
35018                           wayId: wayId,
35019                           fromNodeId: fromNodeId,
35020                           toNodeId: toNodeId
35021                         },
35022                         objectId: wayId,
35023                         objectType: 'way'
35024                       }); // Variables used in the description
35025
35026                       d.replacements = {
35027                         percentage: feature.percentOfTrips,
35028                         num_trips: feature.numberOfTrips,
35029                         highway: linkErrorObject(_t('QA.keepRight.error_parts.highway')),
35030                         from_node: linkEntity('n' + feature.fromNodeId),
35031                         to_node: linkEntity('n' + feature.toNodeId)
35032                       };
35033                       _cache$1.data[d.id] = d;
35034
35035                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
35036                     });
35037                   } // Tiles at high zoom == missing roads
35038
35039
35040                   if (data.tiles) {
35041                     data.tiles.forEach(function (feature) {
35042                       var type = feature.type,
35043                           x = feature.x,
35044                           y = feature.y,
35045                           numberOfTrips = feature.numberOfTrips;
35046                       var geoType = type.toLowerCase();
35047                       var itemId = "".concat(geoType).concat(x).concat(y).concat(numberOfTrips); // Average of recorded points should land on the missing geometry
35048                       // Missing geometry could happen to land on another error
35049
35050                       var loc = pointAverage(feature.points);
35051                       loc = preventCoincident(loc, false);
35052                       var d = new QAItem(loc, _this, "".concat(k, "-").concat(geoType), itemId, {
35053                         issueKey: k,
35054                         identifier: {
35055                           x: x,
35056                           y: y
35057                         }
35058                       });
35059                       d.replacements = {
35060                         num_trips: numberOfTrips,
35061                         geometry_type: _t("QA.improveOSM.geometry_types.".concat(geoType))
35062                       }; // -1 trips indicates data came from a 3rd party
35063
35064                       if (numberOfTrips === -1) {
35065                         d.desc = _t('QA.improveOSM.error_types.mr.description_alt', d.replacements);
35066                       }
35067
35068                       _cache$1.data[d.id] = d;
35069
35070                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
35071                     });
35072                   } // Entities at high zoom == turn restrictions
35073
35074
35075                   if (data.entities) {
35076                     data.entities.forEach(function (feature) {
35077                       var point = feature.point,
35078                           id = feature.id,
35079                           segments = feature.segments,
35080                           numberOfPasses = feature.numberOfPasses,
35081                           turnType = feature.turnType;
35082                       var itemId = "".concat(id.replace(/[,:+#]/g, '_')); // Turn restrictions could be missing at same junction
35083                       // We also want to bump the error up so node is accessible
35084
35085                       var loc = preventCoincident([point.lon, point.lat], true); // Elements are presented in a strange way
35086
35087                       var ids = id.split(',');
35088                       var from_way = ids[0];
35089                       var via_node = ids[3];
35090                       var to_way = ids[2].split(':')[1];
35091                       var d = new QAItem(loc, _this, k, itemId, {
35092                         issueKey: k,
35093                         identifier: id,
35094                         objectId: via_node,
35095                         objectType: 'node'
35096                       }); // Travel direction along from_way clarifies the turn restriction
35097
35098                       var _segments$0$points = _slicedToArray(segments[0].points, 2),
35099                           p1 = _segments$0$points[0],
35100                           p2 = _segments$0$points[1];
35101
35102                       var dir_of_travel = cardinalDirection(relativeBearing(p1, p2)); // Variables used in the description
35103
35104                       d.replacements = {
35105                         num_passed: numberOfPasses,
35106                         num_trips: segments[0].numberOfTrips,
35107                         turn_restriction: turnType.toLowerCase(),
35108                         from_way: linkEntity('w' + from_way),
35109                         to_way: linkEntity('w' + to_way),
35110                         travel_direction: dir_of_travel,
35111                         junction: linkErrorObject(_t('QA.keepRight.error_parts.this_node'))
35112                       };
35113                       _cache$1.data[d.id] = d;
35114
35115                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
35116
35117                       dispatch$2.call('loaded');
35118                     });
35119                   }
35120                 })["catch"](function () {
35121                   delete _cache$1.inflightTile[tile.id][k];
35122
35123                   if (!Object.keys(_cache$1.inflightTile[tile.id]).length) {
35124                     delete _cache$1.inflightTile[tile.id];
35125                     _cache$1.loadedTile[tile.id] = true;
35126                   }
35127                 });
35128               });
35129               _cache$1.inflightTile[tile.id] = requests;
35130             });
35131           },
35132           getComments: function getComments(item) {
35133             var _this2 = this;
35134
35135             // If comments already retrieved no need to do so again
35136             if (item.comments) {
35137               return Promise.resolve(item);
35138             }
35139
35140             var key = item.issueKey;
35141             var qParams = {};
35142
35143             if (key === 'ow') {
35144               qParams = item.identifier;
35145             } else if (key === 'mr') {
35146               qParams.tileX = item.identifier.x;
35147               qParams.tileY = item.identifier.y;
35148             } else if (key === 'tr') {
35149               qParams.targetId = item.identifier;
35150             }
35151
35152             var url = "".concat(_impOsmUrls[key], "/retrieveComments?") + utilQsString(qParams);
35153
35154             var cacheComments = function cacheComments(data) {
35155               // Assign directly for immediate use afterwards
35156               // comments are served newest to oldest
35157               item.comments = data.comments ? data.comments.reverse() : [];
35158
35159               _this2.replaceItem(item);
35160             };
35161
35162             return d3_json(url).then(cacheComments).then(function () {
35163               return item;
35164             });
35165           },
35166           postUpdate: function postUpdate(d, callback) {
35167             if (!serviceOsm.authenticated()) {
35168               // Username required in payload
35169               return callback({
35170                 message: 'Not Authenticated',
35171                 status: -3
35172               }, d);
35173             }
35174
35175             if (_cache$1.inflightPost[d.id]) {
35176               return callback({
35177                 message: 'Error update already inflight',
35178                 status: -2
35179               }, d);
35180             } // Payload can only be sent once username is established
35181
35182
35183             serviceOsm.userDetails(sendPayload.bind(this));
35184
35185             function sendPayload(err, user) {
35186               var _this3 = this;
35187
35188               if (err) {
35189                 return callback(err, d);
35190               }
35191
35192               var key = d.issueKey;
35193               var url = "".concat(_impOsmUrls[key], "/comment");
35194               var payload = {
35195                 username: user.display_name,
35196                 targetIds: [d.identifier]
35197               };
35198
35199               if (d.newStatus) {
35200                 payload.status = d.newStatus;
35201                 payload.text = 'status changed';
35202               } // Comment take place of default text
35203
35204
35205               if (d.newComment) {
35206                 payload.text = d.newComment;
35207               }
35208
35209               var controller = new AbortController();
35210               _cache$1.inflightPost[d.id] = controller;
35211               var options = {
35212                 method: 'POST',
35213                 signal: controller.signal,
35214                 body: JSON.stringify(payload)
35215               };
35216               d3_json(url, options).then(function () {
35217                 delete _cache$1.inflightPost[d.id]; // Just a comment, update error in cache
35218
35219                 if (!d.newStatus) {
35220                   var now = new Date();
35221                   var comments = d.comments ? d.comments : [];
35222                   comments.push({
35223                     username: payload.username,
35224                     text: payload.text,
35225                     timestamp: now.getTime() / 1000
35226                   });
35227
35228                   _this3.replaceItem(d.update({
35229                     comments: comments,
35230                     newComment: undefined
35231                   }));
35232                 } else {
35233                   _this3.removeItem(d);
35234
35235                   if (d.newStatus === 'SOLVED') {
35236                     // Keep track of the number of issues closed per type to tag the changeset
35237                     if (!(d.issueKey in _cache$1.closed)) {
35238                       _cache$1.closed[d.issueKey] = 0;
35239                     }
35240
35241                     _cache$1.closed[d.issueKey] += 1;
35242                   }
35243                 }
35244
35245                 if (callback) callback(null, d);
35246               })["catch"](function (err) {
35247                 delete _cache$1.inflightPost[d.id];
35248                 if (callback) callback(err.message);
35249               });
35250             }
35251           },
35252           // Get all cached QAItems covering the viewport
35253           getItems: function getItems(projection) {
35254             var viewport = projection.clipExtent();
35255             var min = [viewport[0][0], viewport[1][1]];
35256             var max = [viewport[1][0], viewport[0][1]];
35257             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
35258             return _cache$1.rtree.search(bbox).map(function (d) {
35259               return d.data;
35260             });
35261           },
35262           // Get a QAItem from cache
35263           // NOTE: Don't change method name until UI v3 is merged
35264           getError: function getError(id) {
35265             return _cache$1.data[id];
35266           },
35267           // get the name of the icon to display for this item
35268           getIcon: function getIcon(itemType) {
35269             return _impOsmData.icons[itemType];
35270           },
35271           // Replace a single QAItem in the cache
35272           replaceItem: function replaceItem(issue) {
35273             if (!(issue instanceof QAItem) || !issue.id) return;
35274             _cache$1.data[issue.id] = issue;
35275             updateRtree$1(encodeIssueRtree$1(issue), true); // true = replace
35276
35277             return issue;
35278           },
35279           // Remove a single QAItem from the cache
35280           removeItem: function removeItem(issue) {
35281             if (!(issue instanceof QAItem) || !issue.id) return;
35282             delete _cache$1.data[issue.id];
35283             updateRtree$1(encodeIssueRtree$1(issue), false); // false = remove
35284           },
35285           // Used to populate `closed:improveosm:*` changeset tags
35286           getClosedCounts: function getClosedCounts() {
35287             return _cache$1.closed;
35288           }
35289         };
35290
35291         var quot = /"/g;
35292
35293         // B.2.3.2.1 CreateHTML(string, tag, attribute, value)
35294         // https://tc39.github.io/ecma262/#sec-createhtml
35295         var createHtml = function (string, tag, attribute, value) {
35296           var S = String(requireObjectCoercible(string));
35297           var p1 = '<' + tag;
35298           if (attribute !== '') p1 += ' ' + attribute + '="' + String(value).replace(quot, '&quot;') + '"';
35299           return p1 + '>' + S + '</' + tag + '>';
35300         };
35301
35302         // check the existence of a method, lowercase
35303         // of a tag and escaping quotes in arguments
35304         var stringHtmlForced = function (METHOD_NAME) {
35305           return fails(function () {
35306             var test = ''[METHOD_NAME]('"');
35307             return test !== test.toLowerCase() || test.split('"').length > 3;
35308           });
35309         };
35310
35311         // `String.prototype.link` method
35312         // https://tc39.github.io/ecma262/#sec-string.prototype.link
35313         _export({ target: 'String', proto: true, forced: stringHtmlForced('link') }, {
35314           link: function link(url) {
35315             return createHtml(this, 'a', 'href', url);
35316           }
35317         });
35318
35319         var getOwnPropertyDescriptor$4 = objectGetOwnPropertyDescriptor.f;
35320
35321
35322
35323
35324
35325
35326         var nativeEndsWith = ''.endsWith;
35327         var min$8 = Math.min;
35328
35329         var CORRECT_IS_REGEXP_LOGIC = correctIsRegexpLogic('endsWith');
35330         // https://github.com/zloirock/core-js/pull/702
35331         var MDN_POLYFILL_BUG =  !CORRECT_IS_REGEXP_LOGIC && !!function () {
35332           var descriptor = getOwnPropertyDescriptor$4(String.prototype, 'endsWith');
35333           return descriptor && !descriptor.writable;
35334         }();
35335
35336         // `String.prototype.endsWith` method
35337         // https://tc39.github.io/ecma262/#sec-string.prototype.endswith
35338         _export({ target: 'String', proto: true, forced: !MDN_POLYFILL_BUG && !CORRECT_IS_REGEXP_LOGIC }, {
35339           endsWith: function endsWith(searchString /* , endPosition = @length */) {
35340             var that = String(requireObjectCoercible(this));
35341             notARegexp(searchString);
35342             var endPosition = arguments.length > 1 ? arguments[1] : undefined;
35343             var len = toLength(that.length);
35344             var end = endPosition === undefined ? len : min$8(toLength(endPosition), len);
35345             var search = String(searchString);
35346             return nativeEndsWith
35347               ? nativeEndsWith.call(that, search, end)
35348               : that.slice(end - search.length, end) === search;
35349           }
35350         });
35351
35352         var getOwnPropertyDescriptor$5 = objectGetOwnPropertyDescriptor.f;
35353
35354
35355
35356
35357
35358
35359         var nativeStartsWith = ''.startsWith;
35360         var min$9 = Math.min;
35361
35362         var CORRECT_IS_REGEXP_LOGIC$1 = correctIsRegexpLogic('startsWith');
35363         // https://github.com/zloirock/core-js/pull/702
35364         var MDN_POLYFILL_BUG$1 =  !CORRECT_IS_REGEXP_LOGIC$1 && !!function () {
35365           var descriptor = getOwnPropertyDescriptor$5(String.prototype, 'startsWith');
35366           return descriptor && !descriptor.writable;
35367         }();
35368
35369         // `String.prototype.startsWith` method
35370         // https://tc39.github.io/ecma262/#sec-string.prototype.startswith
35371         _export({ target: 'String', proto: true, forced: !MDN_POLYFILL_BUG$1 && !CORRECT_IS_REGEXP_LOGIC$1 }, {
35372           startsWith: function startsWith(searchString /* , position = 0 */) {
35373             var that = String(requireObjectCoercible(this));
35374             notARegexp(searchString);
35375             var index = toLength(min$9(arguments.length > 1 ? arguments[1] : undefined, that.length));
35376             var search = String(searchString);
35377             return nativeStartsWith
35378               ? nativeStartsWith.call(that, search, index)
35379               : that.slice(index, index + search.length) === search;
35380           }
35381         });
35382
35383         var $trimEnd = stringTrim.end;
35384
35385
35386         var FORCED$e = stringTrimForced('trimEnd');
35387
35388         var trimEnd = FORCED$e ? function trimEnd() {
35389           return $trimEnd(this);
35390         } : ''.trimEnd;
35391
35392         // `String.prototype.{ trimEnd, trimRight }` methods
35393         // https://github.com/tc39/ecmascript-string-left-right-trim
35394         _export({ target: 'String', proto: true, forced: FORCED$e }, {
35395           trimEnd: trimEnd,
35396           trimRight: trimEnd
35397         });
35398
35399         var defaults = createCommonjsModule(function (module) {
35400           function getDefaults() {
35401             return {
35402               baseUrl: null,
35403               breaks: false,
35404               gfm: true,
35405               headerIds: true,
35406               headerPrefix: '',
35407               highlight: null,
35408               langPrefix: 'language-',
35409               mangle: true,
35410               pedantic: false,
35411               renderer: null,
35412               sanitize: false,
35413               sanitizer: null,
35414               silent: false,
35415               smartLists: false,
35416               smartypants: false,
35417               tokenizer: null,
35418               walkTokens: null,
35419               xhtml: false
35420             };
35421           }
35422
35423           function changeDefaults(newDefaults) {
35424             module.exports.defaults = newDefaults;
35425           }
35426
35427           module.exports = {
35428             defaults: getDefaults(),
35429             getDefaults: getDefaults,
35430             changeDefaults: changeDefaults
35431           };
35432         });
35433
35434         /**
35435          * Helpers
35436          */
35437         var escapeTest = /[&<>"']/;
35438         var escapeReplace = /[&<>"']/g;
35439         var escapeTestNoEncode = /[<>"']|&(?!#?\w+;)/;
35440         var escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g;
35441         var escapeReplacements = {
35442           '&': '&amp;',
35443           '<': '&lt;',
35444           '>': '&gt;',
35445           '"': '&quot;',
35446           "'": '&#39;'
35447         };
35448
35449         var getEscapeReplacement = function getEscapeReplacement(ch) {
35450           return escapeReplacements[ch];
35451         };
35452
35453         function escape$1(html, encode) {
35454           if (encode) {
35455             if (escapeTest.test(html)) {
35456               return html.replace(escapeReplace, getEscapeReplacement);
35457             }
35458           } else {
35459             if (escapeTestNoEncode.test(html)) {
35460               return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
35461             }
35462           }
35463
35464           return html;
35465         }
35466
35467         var unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
35468
35469         function unescape$1(html) {
35470           // explicitly match decimal, hex, and named HTML entities
35471           return html.replace(unescapeTest, function (_, n) {
35472             n = n.toLowerCase();
35473             if (n === 'colon') return ':';
35474
35475             if (n.charAt(0) === '#') {
35476               return n.charAt(1) === 'x' ? String.fromCharCode(parseInt(n.substring(2), 16)) : String.fromCharCode(+n.substring(1));
35477             }
35478
35479             return '';
35480           });
35481         }
35482
35483         var caret = /(^|[^\[])\^/g;
35484
35485         function edit(regex, opt) {
35486           regex = regex.source || regex;
35487           opt = opt || '';
35488           var obj = {
35489             replace: function replace(name, val) {
35490               val = val.source || val;
35491               val = val.replace(caret, '$1');
35492               regex = regex.replace(name, val);
35493               return obj;
35494             },
35495             getRegex: function getRegex() {
35496               return new RegExp(regex, opt);
35497             }
35498           };
35499           return obj;
35500         }
35501
35502         var nonWordAndColonTest = /[^\w:]/g;
35503         var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
35504
35505         function cleanUrl(sanitize, base, href) {
35506           if (sanitize) {
35507             var prot;
35508
35509             try {
35510               prot = decodeURIComponent(unescape$1(href)).replace(nonWordAndColonTest, '').toLowerCase();
35511             } catch (e) {
35512               return null;
35513             }
35514
35515             if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
35516               return null;
35517             }
35518           }
35519
35520           if (base && !originIndependentUrl.test(href)) {
35521             href = resolveUrl(base, href);
35522           }
35523
35524           try {
35525             href = encodeURI(href).replace(/%25/g, '%');
35526           } catch (e) {
35527             return null;
35528           }
35529
35530           return href;
35531         }
35532
35533         var baseUrls = {};
35534         var justDomain = /^[^:]+:\/*[^/]*$/;
35535         var protocol = /^([^:]+:)[\s\S]*$/;
35536         var domain = /^([^:]+:\/*[^/]*)[\s\S]*$/;
35537
35538         function resolveUrl(base, href) {
35539           if (!baseUrls[' ' + base]) {
35540             // we can ignore everything in base after the last slash of its path component,
35541             // but we might need to add _that_
35542             // https://tools.ietf.org/html/rfc3986#section-3
35543             if (justDomain.test(base)) {
35544               baseUrls[' ' + base] = base + '/';
35545             } else {
35546               baseUrls[' ' + base] = rtrim$1(base, '/', true);
35547             }
35548           }
35549
35550           base = baseUrls[' ' + base];
35551           var relativeBase = base.indexOf(':') === -1;
35552
35553           if (href.substring(0, 2) === '//') {
35554             if (relativeBase) {
35555               return href;
35556             }
35557
35558             return base.replace(protocol, '$1') + href;
35559           } else if (href.charAt(0) === '/') {
35560             if (relativeBase) {
35561               return href;
35562             }
35563
35564             return base.replace(domain, '$1') + href;
35565           } else {
35566             return base + href;
35567           }
35568         }
35569
35570         var noopTest = {
35571           exec: function noopTest() {}
35572         };
35573
35574         function merge$1(obj) {
35575           var i = 1,
35576               target,
35577               key;
35578
35579           for (; i < arguments.length; i++) {
35580             target = arguments[i];
35581
35582             for (key in target) {
35583               if (Object.prototype.hasOwnProperty.call(target, key)) {
35584                 obj[key] = target[key];
35585               }
35586             }
35587           }
35588
35589           return obj;
35590         }
35591
35592         function splitCells(tableRow, count) {
35593           // ensure that every cell-delimiting pipe has a space
35594           // before it to distinguish it from an escaped pipe
35595           var row = tableRow.replace(/\|/g, function (match, offset, str) {
35596             var escaped = false,
35597                 curr = offset;
35598
35599             while (--curr >= 0 && str[curr] === '\\') {
35600               escaped = !escaped;
35601             }
35602
35603             if (escaped) {
35604               // odd number of slashes means | is escaped
35605               // so we leave it alone
35606               return '|';
35607             } else {
35608               // add space before unescaped |
35609               return ' |';
35610             }
35611           }),
35612               cells = row.split(/ \|/);
35613           var i = 0;
35614
35615           if (cells.length > count) {
35616             cells.splice(count);
35617           } else {
35618             while (cells.length < count) {
35619               cells.push('');
35620             }
35621           }
35622
35623           for (; i < cells.length; i++) {
35624             // leading or trailing whitespace is ignored per the gfm spec
35625             cells[i] = cells[i].trim().replace(/\\\|/g, '|');
35626           }
35627
35628           return cells;
35629         } // Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
35630         // /c*$/ is vulnerable to REDOS.
35631         // invert: Remove suffix of non-c chars instead. Default falsey.
35632
35633
35634         function rtrim$1(str, c, invert) {
35635           var l = str.length;
35636
35637           if (l === 0) {
35638             return '';
35639           } // Length of suffix matching the invert condition.
35640
35641
35642           var suffLen = 0; // Step left until we fail to match the invert condition.
35643
35644           while (suffLen < l) {
35645             var currChar = str.charAt(l - suffLen - 1);
35646
35647             if (currChar === c && !invert) {
35648               suffLen++;
35649             } else if (currChar !== c && invert) {
35650               suffLen++;
35651             } else {
35652               break;
35653             }
35654           }
35655
35656           return str.substr(0, l - suffLen);
35657         }
35658
35659         function findClosingBracket(str, b) {
35660           if (str.indexOf(b[1]) === -1) {
35661             return -1;
35662           }
35663
35664           var l = str.length;
35665           var level = 0,
35666               i = 0;
35667
35668           for (; i < l; i++) {
35669             if (str[i] === '\\') {
35670               i++;
35671             } else if (str[i] === b[0]) {
35672               level++;
35673             } else if (str[i] === b[1]) {
35674               level--;
35675
35676               if (level < 0) {
35677                 return i;
35678               }
35679             }
35680           }
35681
35682           return -1;
35683         }
35684
35685         function checkSanitizeDeprecation(opt) {
35686           if (opt && opt.sanitize && !opt.silent) {
35687             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');
35688           }
35689         } // copied from https://stackoverflow.com/a/5450113/806777
35690
35691
35692         function repeatString(pattern, count) {
35693           if (count < 1) {
35694             return '';
35695           }
35696
35697           var result = '';
35698
35699           while (count > 1) {
35700             if (count & 1) {
35701               result += pattern;
35702             }
35703
35704             count >>= 1;
35705             pattern += pattern;
35706           }
35707
35708           return result + pattern;
35709         }
35710
35711         var helpers = {
35712           escape: escape$1,
35713           unescape: unescape$1,
35714           edit: edit,
35715           cleanUrl: cleanUrl,
35716           resolveUrl: resolveUrl,
35717           noopTest: noopTest,
35718           merge: merge$1,
35719           splitCells: splitCells,
35720           rtrim: rtrim$1,
35721           findClosingBracket: findClosingBracket,
35722           checkSanitizeDeprecation: checkSanitizeDeprecation,
35723           repeatString: repeatString
35724         };
35725
35726         var defaults$1 = defaults.defaults;
35727         var rtrim$2 = helpers.rtrim,
35728             splitCells$1 = helpers.splitCells,
35729             _escape = helpers.escape,
35730             findClosingBracket$1 = helpers.findClosingBracket;
35731
35732         function outputLink(cap, link, raw) {
35733           var href = link.href;
35734           var title = link.title ? _escape(link.title) : null;
35735           var text = cap[1].replace(/\\([\[\]])/g, '$1');
35736
35737           if (cap[0].charAt(0) !== '!') {
35738             return {
35739               type: 'link',
35740               raw: raw,
35741               href: href,
35742               title: title,
35743               text: text
35744             };
35745           } else {
35746             return {
35747               type: 'image',
35748               raw: raw,
35749               href: href,
35750               title: title,
35751               text: _escape(text)
35752             };
35753           }
35754         }
35755
35756         function indentCodeCompensation(raw, text) {
35757           var matchIndentToCode = raw.match(/^(\s+)(?:```)/);
35758
35759           if (matchIndentToCode === null) {
35760             return text;
35761           }
35762
35763           var indentToCode = matchIndentToCode[1];
35764           return text.split('\n').map(function (node) {
35765             var matchIndentInNode = node.match(/^\s+/);
35766
35767             if (matchIndentInNode === null) {
35768               return node;
35769             }
35770
35771             var _matchIndentInNode = _slicedToArray(matchIndentInNode, 1),
35772                 indentInNode = _matchIndentInNode[0];
35773
35774             if (indentInNode.length >= indentToCode.length) {
35775               return node.slice(indentToCode.length);
35776             }
35777
35778             return node;
35779           }).join('\n');
35780         }
35781         /**
35782          * Tokenizer
35783          */
35784
35785
35786         var Tokenizer_1 = /*#__PURE__*/function () {
35787           function Tokenizer(options) {
35788             _classCallCheck(this, Tokenizer);
35789
35790             this.options = options || defaults$1;
35791           }
35792
35793           _createClass(Tokenizer, [{
35794             key: "space",
35795             value: function space(src) {
35796               var cap = this.rules.block.newline.exec(src);
35797
35798               if (cap) {
35799                 if (cap[0].length > 1) {
35800                   return {
35801                     type: 'space',
35802                     raw: cap[0]
35803                   };
35804                 }
35805
35806                 return {
35807                   raw: '\n'
35808                 };
35809               }
35810             }
35811           }, {
35812             key: "code",
35813             value: function code(src, tokens) {
35814               var cap = this.rules.block.code.exec(src);
35815
35816               if (cap) {
35817                 var lastToken = tokens[tokens.length - 1]; // An indented code block cannot interrupt a paragraph.
35818
35819                 if (lastToken && lastToken.type === 'paragraph') {
35820                   return {
35821                     raw: cap[0],
35822                     text: cap[0].trimRight()
35823                   };
35824                 }
35825
35826                 var text = cap[0].replace(/^ {4}/gm, '');
35827                 return {
35828                   type: 'code',
35829                   raw: cap[0],
35830                   codeBlockStyle: 'indented',
35831                   text: !this.options.pedantic ? rtrim$2(text, '\n') : text
35832                 };
35833               }
35834             }
35835           }, {
35836             key: "fences",
35837             value: function fences(src) {
35838               var cap = this.rules.block.fences.exec(src);
35839
35840               if (cap) {
35841                 var raw = cap[0];
35842                 var text = indentCodeCompensation(raw, cap[3] || '');
35843                 return {
35844                   type: 'code',
35845                   raw: raw,
35846                   lang: cap[2] ? cap[2].trim() : cap[2],
35847                   text: text
35848                 };
35849               }
35850             }
35851           }, {
35852             key: "heading",
35853             value: function heading(src) {
35854               var cap = this.rules.block.heading.exec(src);
35855
35856               if (cap) {
35857                 return {
35858                   type: 'heading',
35859                   raw: cap[0],
35860                   depth: cap[1].length,
35861                   text: cap[2]
35862                 };
35863               }
35864             }
35865           }, {
35866             key: "nptable",
35867             value: function nptable(src) {
35868               var cap = this.rules.block.nptable.exec(src);
35869
35870               if (cap) {
35871                 var item = {
35872                   type: 'table',
35873                   header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')),
35874                   align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
35875                   cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [],
35876                   raw: cap[0]
35877                 };
35878
35879                 if (item.header.length === item.align.length) {
35880                   var l = item.align.length;
35881                   var i;
35882
35883                   for (i = 0; i < l; i++) {
35884                     if (/^ *-+: *$/.test(item.align[i])) {
35885                       item.align[i] = 'right';
35886                     } else if (/^ *:-+: *$/.test(item.align[i])) {
35887                       item.align[i] = 'center';
35888                     } else if (/^ *:-+ *$/.test(item.align[i])) {
35889                       item.align[i] = 'left';
35890                     } else {
35891                       item.align[i] = null;
35892                     }
35893                   }
35894
35895                   l = item.cells.length;
35896
35897                   for (i = 0; i < l; i++) {
35898                     item.cells[i] = splitCells$1(item.cells[i], item.header.length);
35899                   }
35900
35901                   return item;
35902                 }
35903               }
35904             }
35905           }, {
35906             key: "hr",
35907             value: function hr(src) {
35908               var cap = this.rules.block.hr.exec(src);
35909
35910               if (cap) {
35911                 return {
35912                   type: 'hr',
35913                   raw: cap[0]
35914                 };
35915               }
35916             }
35917           }, {
35918             key: "blockquote",
35919             value: function blockquote(src) {
35920               var cap = this.rules.block.blockquote.exec(src);
35921
35922               if (cap) {
35923                 var text = cap[0].replace(/^ *> ?/gm, '');
35924                 return {
35925                   type: 'blockquote',
35926                   raw: cap[0],
35927                   text: text
35928                 };
35929               }
35930             }
35931           }, {
35932             key: "list",
35933             value: function list(src) {
35934               var cap = this.rules.block.list.exec(src);
35935
35936               if (cap) {
35937                 var raw = cap[0];
35938                 var bull = cap[2];
35939                 var isordered = bull.length > 1;
35940                 var isparen = bull[bull.length - 1] === ')';
35941                 var list = {
35942                   type: 'list',
35943                   raw: raw,
35944                   ordered: isordered,
35945                   start: isordered ? +bull.slice(0, -1) : '',
35946                   loose: false,
35947                   items: []
35948                 }; // Get each top-level item.
35949
35950                 var itemMatch = cap[0].match(this.rules.block.item);
35951                 var next = false,
35952                     item,
35953                     space,
35954                     b,
35955                     addBack,
35956                     loose,
35957                     istask,
35958                     ischecked;
35959                 var l = itemMatch.length;
35960
35961                 for (var i = 0; i < l; i++) {
35962                   item = itemMatch[i];
35963                   raw = item; // Remove the list item's bullet
35964                   // so it is seen as the next token.
35965
35966                   space = item.length;
35967                   item = item.replace(/^ *([*+-]|\d+[.)]) ?/, ''); // Outdent whatever the
35968                   // list item contains. Hacky.
35969
35970                   if (~item.indexOf('\n ')) {
35971                     space -= item.length;
35972                     item = !this.options.pedantic ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') : item.replace(/^ {1,4}/gm, '');
35973                   } // Determine whether the next list item belongs here.
35974                   // Backpedal if it does not belong in this list.
35975
35976
35977                   if (i !== l - 1) {
35978                     b = this.rules.block.bullet.exec(itemMatch[i + 1])[0];
35979
35980                     if (isordered ? b.length === 1 || !isparen && b[b.length - 1] === ')' : b.length > 1 || this.options.smartLists && b !== bull) {
35981                       addBack = itemMatch.slice(i + 1).join('\n');
35982                       list.raw = list.raw.substring(0, list.raw.length - addBack.length);
35983                       i = l - 1;
35984                     }
35985                   } // Determine whether item is loose or not.
35986                   // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
35987                   // for discount behavior.
35988
35989
35990                   loose = next || /\n\n(?!\s*$)/.test(item);
35991
35992                   if (i !== l - 1) {
35993                     next = item.charAt(item.length - 1) === '\n';
35994                     if (!loose) loose = next;
35995                   }
35996
35997                   if (loose) {
35998                     list.loose = true;
35999                   } // Check for task list items
36000
36001
36002                   istask = /^\[[ xX]\] /.test(item);
36003                   ischecked = undefined;
36004
36005                   if (istask) {
36006                     ischecked = item[1] !== ' ';
36007                     item = item.replace(/^\[[ xX]\] +/, '');
36008                   }
36009
36010                   list.items.push({
36011                     type: 'list_item',
36012                     raw: raw,
36013                     task: istask,
36014                     checked: ischecked,
36015                     loose: loose,
36016                     text: item
36017                   });
36018                 }
36019
36020                 return list;
36021               }
36022             }
36023           }, {
36024             key: "html",
36025             value: function html(src) {
36026               var cap = this.rules.block.html.exec(src);
36027
36028               if (cap) {
36029                 return {
36030                   type: this.options.sanitize ? 'paragraph' : 'html',
36031                   raw: cap[0],
36032                   pre: !this.options.sanitizer && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
36033                   text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]
36034                 };
36035               }
36036             }
36037           }, {
36038             key: "def",
36039             value: function def(src) {
36040               var cap = this.rules.block.def.exec(src);
36041
36042               if (cap) {
36043                 if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1);
36044                 var tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
36045                 return {
36046                   tag: tag,
36047                   raw: cap[0],
36048                   href: cap[2],
36049                   title: cap[3]
36050                 };
36051               }
36052             }
36053           }, {
36054             key: "table",
36055             value: function table(src) {
36056               var cap = this.rules.block.table.exec(src);
36057
36058               if (cap) {
36059                 var item = {
36060                   type: 'table',
36061                   header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')),
36062                   align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
36063                   cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
36064                 };
36065
36066                 if (item.header.length === item.align.length) {
36067                   item.raw = cap[0];
36068                   var l = item.align.length;
36069                   var i;
36070
36071                   for (i = 0; i < l; i++) {
36072                     if (/^ *-+: *$/.test(item.align[i])) {
36073                       item.align[i] = 'right';
36074                     } else if (/^ *:-+: *$/.test(item.align[i])) {
36075                       item.align[i] = 'center';
36076                     } else if (/^ *:-+ *$/.test(item.align[i])) {
36077                       item.align[i] = 'left';
36078                     } else {
36079                       item.align[i] = null;
36080                     }
36081                   }
36082
36083                   l = item.cells.length;
36084
36085                   for (i = 0; i < l; i++) {
36086                     item.cells[i] = splitCells$1(item.cells[i].replace(/^ *\| *| *\| *$/g, ''), item.header.length);
36087                   }
36088
36089                   return item;
36090                 }
36091               }
36092             }
36093           }, {
36094             key: "lheading",
36095             value: function lheading(src) {
36096               var cap = this.rules.block.lheading.exec(src);
36097
36098               if (cap) {
36099                 return {
36100                   type: 'heading',
36101                   raw: cap[0],
36102                   depth: cap[2].charAt(0) === '=' ? 1 : 2,
36103                   text: cap[1]
36104                 };
36105               }
36106             }
36107           }, {
36108             key: "paragraph",
36109             value: function paragraph(src) {
36110               var cap = this.rules.block.paragraph.exec(src);
36111
36112               if (cap) {
36113                 return {
36114                   type: 'paragraph',
36115                   raw: cap[0],
36116                   text: cap[1].charAt(cap[1].length - 1) === '\n' ? cap[1].slice(0, -1) : cap[1]
36117                 };
36118               }
36119             }
36120           }, {
36121             key: "text",
36122             value: function text(src, tokens) {
36123               var cap = this.rules.block.text.exec(src);
36124
36125               if (cap) {
36126                 var lastToken = tokens[tokens.length - 1];
36127
36128                 if (lastToken && lastToken.type === 'text') {
36129                   return {
36130                     raw: cap[0],
36131                     text: cap[0]
36132                   };
36133                 }
36134
36135                 return {
36136                   type: 'text',
36137                   raw: cap[0],
36138                   text: cap[0]
36139                 };
36140               }
36141             }
36142           }, {
36143             key: "escape",
36144             value: function escape(src) {
36145               var cap = this.rules.inline.escape.exec(src);
36146
36147               if (cap) {
36148                 return {
36149                   type: 'escape',
36150                   raw: cap[0],
36151                   text: _escape(cap[1])
36152                 };
36153               }
36154             }
36155           }, {
36156             key: "tag",
36157             value: function tag(src, inLink, inRawBlock) {
36158               var cap = this.rules.inline.tag.exec(src);
36159
36160               if (cap) {
36161                 if (!inLink && /^<a /i.test(cap[0])) {
36162                   inLink = true;
36163                 } else if (inLink && /^<\/a>/i.test(cap[0])) {
36164                   inLink = false;
36165                 }
36166
36167                 if (!inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
36168                   inRawBlock = true;
36169                 } else if (inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
36170                   inRawBlock = false;
36171                 }
36172
36173                 return {
36174                   type: this.options.sanitize ? 'text' : 'html',
36175                   raw: cap[0],
36176                   inLink: inLink,
36177                   inRawBlock: inRawBlock,
36178                   text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]
36179                 };
36180               }
36181             }
36182           }, {
36183             key: "link",
36184             value: function link(src) {
36185               var cap = this.rules.inline.link.exec(src);
36186
36187               if (cap) {
36188                 var lastParenIndex = findClosingBracket$1(cap[2], '()');
36189
36190                 if (lastParenIndex > -1) {
36191                   var start = cap[0].indexOf('!') === 0 ? 5 : 4;
36192                   var linkLen = start + cap[1].length + lastParenIndex;
36193                   cap[2] = cap[2].substring(0, lastParenIndex);
36194                   cap[0] = cap[0].substring(0, linkLen).trim();
36195                   cap[3] = '';
36196                 }
36197
36198                 var href = cap[2];
36199                 var title = '';
36200
36201                 if (this.options.pedantic) {
36202                   var link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
36203
36204                   if (link) {
36205                     href = link[1];
36206                     title = link[3];
36207                   } else {
36208                     title = '';
36209                   }
36210                 } else {
36211                   title = cap[3] ? cap[3].slice(1, -1) : '';
36212                 }
36213
36214                 href = href.trim().replace(/^<([\s\S]*)>$/, '$1');
36215                 var token = outputLink(cap, {
36216                   href: href ? href.replace(this.rules.inline._escapes, '$1') : href,
36217                   title: title ? title.replace(this.rules.inline._escapes, '$1') : title
36218                 }, cap[0]);
36219                 return token;
36220               }
36221             }
36222           }, {
36223             key: "reflink",
36224             value: function reflink(src, links) {
36225               var cap;
36226
36227               if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) {
36228                 var link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
36229                 link = links[link.toLowerCase()];
36230
36231                 if (!link || !link.href) {
36232                   var text = cap[0].charAt(0);
36233                   return {
36234                     type: 'text',
36235                     raw: text,
36236                     text: text
36237                   };
36238                 }
36239
36240                 var token = outputLink(cap, link, cap[0]);
36241                 return token;
36242               }
36243             }
36244           }, {
36245             key: "strong",
36246             value: function strong(src, maskedSrc) {
36247               var prevChar = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
36248               var match = this.rules.inline.strong.start.exec(src);
36249
36250               if (match && (!match[1] || match[1] && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar)))) {
36251                 maskedSrc = maskedSrc.slice(-1 * src.length);
36252                 var endReg = match[0] === '**' ? this.rules.inline.strong.endAst : this.rules.inline.strong.endUnd;
36253                 endReg.lastIndex = 0;
36254                 var cap;
36255
36256                 while ((match = endReg.exec(maskedSrc)) != null) {
36257                   cap = this.rules.inline.strong.middle.exec(maskedSrc.slice(0, match.index + 3));
36258
36259                   if (cap) {
36260                     return {
36261                       type: 'strong',
36262                       raw: src.slice(0, cap[0].length),
36263                       text: src.slice(2, cap[0].length - 2)
36264                     };
36265                   }
36266                 }
36267               }
36268             }
36269           }, {
36270             key: "em",
36271             value: function em(src, maskedSrc) {
36272               var prevChar = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
36273               var match = this.rules.inline.em.start.exec(src);
36274
36275               if (match && (!match[1] || match[1] && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar)))) {
36276                 maskedSrc = maskedSrc.slice(-1 * src.length);
36277                 var endReg = match[0] === '*' ? this.rules.inline.em.endAst : this.rules.inline.em.endUnd;
36278                 endReg.lastIndex = 0;
36279                 var cap;
36280
36281                 while ((match = endReg.exec(maskedSrc)) != null) {
36282                   cap = this.rules.inline.em.middle.exec(maskedSrc.slice(0, match.index + 2));
36283
36284                   if (cap) {
36285                     return {
36286                       type: 'em',
36287                       raw: src.slice(0, cap[0].length),
36288                       text: src.slice(1, cap[0].length - 1)
36289                     };
36290                   }
36291                 }
36292               }
36293             }
36294           }, {
36295             key: "codespan",
36296             value: function codespan(src) {
36297               var cap = this.rules.inline.code.exec(src);
36298
36299               if (cap) {
36300                 var text = cap[2].replace(/\n/g, ' ');
36301                 var hasNonSpaceChars = /[^ ]/.test(text);
36302                 var hasSpaceCharsOnBothEnds = text.startsWith(' ') && text.endsWith(' ');
36303
36304                 if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
36305                   text = text.substring(1, text.length - 1);
36306                 }
36307
36308                 text = _escape(text, true);
36309                 return {
36310                   type: 'codespan',
36311                   raw: cap[0],
36312                   text: text
36313                 };
36314               }
36315             }
36316           }, {
36317             key: "br",
36318             value: function br(src) {
36319               var cap = this.rules.inline.br.exec(src);
36320
36321               if (cap) {
36322                 return {
36323                   type: 'br',
36324                   raw: cap[0]
36325                 };
36326               }
36327             }
36328           }, {
36329             key: "del",
36330             value: function del(src) {
36331               var cap = this.rules.inline.del.exec(src);
36332
36333               if (cap) {
36334                 return {
36335                   type: 'del',
36336                   raw: cap[0],
36337                   text: cap[1]
36338                 };
36339               }
36340             }
36341           }, {
36342             key: "autolink",
36343             value: function autolink(src, mangle) {
36344               var cap = this.rules.inline.autolink.exec(src);
36345
36346               if (cap) {
36347                 var text, href;
36348
36349                 if (cap[2] === '@') {
36350                   text = _escape(this.options.mangle ? mangle(cap[1]) : cap[1]);
36351                   href = 'mailto:' + text;
36352                 } else {
36353                   text = _escape(cap[1]);
36354                   href = text;
36355                 }
36356
36357                 return {
36358                   type: 'link',
36359                   raw: cap[0],
36360                   text: text,
36361                   href: href,
36362                   tokens: [{
36363                     type: 'text',
36364                     raw: text,
36365                     text: text
36366                   }]
36367                 };
36368               }
36369             }
36370           }, {
36371             key: "url",
36372             value: function url(src, mangle) {
36373               var cap;
36374
36375               if (cap = this.rules.inline.url.exec(src)) {
36376                 var text, href;
36377
36378                 if (cap[2] === '@') {
36379                   text = _escape(this.options.mangle ? mangle(cap[0]) : cap[0]);
36380                   href = 'mailto:' + text;
36381                 } else {
36382                   // do extended autolink path validation
36383                   var prevCapZero;
36384
36385                   do {
36386                     prevCapZero = cap[0];
36387                     cap[0] = this.rules.inline._backpedal.exec(cap[0])[0];
36388                   } while (prevCapZero !== cap[0]);
36389
36390                   text = _escape(cap[0]);
36391
36392                   if (cap[1] === 'www.') {
36393                     href = 'http://' + text;
36394                   } else {
36395                     href = text;
36396                   }
36397                 }
36398
36399                 return {
36400                   type: 'link',
36401                   raw: cap[0],
36402                   text: text,
36403                   href: href,
36404                   tokens: [{
36405                     type: 'text',
36406                     raw: text,
36407                     text: text
36408                   }]
36409                 };
36410               }
36411             }
36412           }, {
36413             key: "inlineText",
36414             value: function inlineText(src, inRawBlock, smartypants) {
36415               var cap = this.rules.inline.text.exec(src);
36416
36417               if (cap) {
36418                 var text;
36419
36420                 if (inRawBlock) {
36421                   text = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0];
36422                 } else {
36423                   text = _escape(this.options.smartypants ? smartypants(cap[0]) : cap[0]);
36424                 }
36425
36426                 return {
36427                   type: 'text',
36428                   raw: cap[0],
36429                   text: text
36430                 };
36431               }
36432             }
36433           }]);
36434
36435           return Tokenizer;
36436         }();
36437
36438         var noopTest$1 = helpers.noopTest,
36439             edit$1 = helpers.edit,
36440             merge$2 = helpers.merge;
36441         /**
36442          * Block-Level Grammar
36443          */
36444
36445         var block = {
36446           newline: /^\n+/,
36447           code: /^( {4}[^\n]+\n*)+/,
36448           fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,
36449           hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
36450           heading: /^ {0,3}(#{1,6}) +([^\n]*?)(?: +#+)? *(?:\n+|$)/,
36451           blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
36452           list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
36453           html: '^ {0,3}(?:' // optional indentation
36454           + '<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
36455           + '|comment[^\\n]*(\\n+|$)' // (2)
36456           + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
36457           + '|<![A-Z][\\s\\S]*?(?:>\\n*|$)' // (4)
36458           + '|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)' // (5)
36459           + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)' // (6)
36460           + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag
36461           + '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag
36462           + ')',
36463           def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
36464           nptable: noopTest$1,
36465           table: noopTest$1,
36466           lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
36467           // regex template, placeholders will be replaced according to different paragraph
36468           // interruption rules of commonmark and the original markdown spec:
36469           _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,
36470           text: /^[^\n]+/
36471         };
36472         block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
36473         block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
36474         block.def = edit$1(block.def).replace('label', block._label).replace('title', block._title).getRegex();
36475         block.bullet = /(?:[*+-]|\d{1,9}[.)])/;
36476         block.item = /^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/;
36477         block.item = edit$1(block.item, 'gm').replace(/bull/g, block.bullet).getRegex();
36478         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();
36479         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';
36480         block._comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
36481         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();
36482         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
36483         .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
36484         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
36485         .getRegex();
36486         block.blockquote = edit$1(block.blockquote).replace('paragraph', block.paragraph).getRegex();
36487         /**
36488          * Normal Block Grammar
36489          */
36490
36491         block.normal = merge$2({}, block);
36492         /**
36493          * GFM Block Grammar
36494          */
36495
36496         block.gfm = merge$2({}, block.normal, {
36497           nptable: '^ *([^|\\n ].*\\|.*)\\n' // Header
36498           + ' {0,3}([-:]+ *\\|[-| :]*)' // Align
36499           + '(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)',
36500           // Cells
36501           table: '^ *\\|(.+)\\n' // Header
36502           + ' {0,3}\\|?( *[-:]+[-| :]*)' // Align
36503           + '(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
36504
36505         });
36506         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
36507         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
36508         .getRegex();
36509         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
36510         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
36511         .getRegex();
36512         /**
36513          * Pedantic grammar (original John Gruber's loose markdown specification)
36514          */
36515
36516         block.pedantic = merge$2({}, block.normal, {
36517           html: edit$1('^ *(?:comment *(?:\\n|\\s*$)' + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
36518           + '|<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(),
36519           def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
36520           heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,
36521           fences: noopTest$1,
36522           // fences not supported
36523           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()
36524         });
36525         /**
36526          * Inline-Level Grammar
36527          */
36528
36529         var inline = {
36530           escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
36531           autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
36532           url: noopTest$1,
36533           tag: '^comment' + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
36534           + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
36535           + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
36536           + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
36537           + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>',
36538           // CDATA section
36539           link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
36540           reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
36541           nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
36542           reflinkSearch: 'reflink|nolink(?!\\()',
36543           strong: {
36544             start: /^(?:(\*\*(?=[*punctuation]))|\*\*)(?![\s])|__/,
36545             // (1) returns if starts w/ punctuation
36546             middle: /^\*\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*\*$|^__(?![\s])((?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?)__$/,
36547             endAst: /[^punctuation\s]\*\*(?!\*)|[punctuation]\*\*(?!\*)(?:(?=[punctuation_\s]|$))/,
36548             // last char can't be punct, or final * must also be followed by punct (or endline)
36549             endUnd: /[^\s]__(?!_)(?:(?=[punctuation*\s])|$)/ // last char can't be a space, and final _ must preceed punct or \s (or endline)
36550
36551           },
36552           em: {
36553             start: /^(?:(\*(?=[punctuation]))|\*)(?![*\s])|_/,
36554             // (1) returns if starts w/ punctuation
36555             middle: /^\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*$|^_(?![_\s])(?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?_$/,
36556             endAst: /[^punctuation\s]\*(?!\*)|[punctuation]\*(?!\*)(?:(?=[punctuation_\s]|$))/,
36557             // last char can't be punct, or final * must also be followed by punct (or endline)
36558             endUnd: /[^\s]_(?!_)(?:(?=[punctuation*\s])|$)/ // last char can't be a space, and final _ must preceed punct or \s (or endline)
36559
36560           },
36561           code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
36562           br: /^( {2,}|\\)\n(?!\s*$)/,
36563           del: noopTest$1,
36564           text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {2,}\n)))/,
36565           punctuation: /^([\s*punctuation])/
36566         }; // list of punctuation marks from common mark spec
36567         // without * and _ to workaround cases with double emphasis
36568
36569         inline._punctuation = '!"#$%&\'()+\\-.,/:;<=>?@\\[\\]`^{|}~';
36570         inline.punctuation = edit$1(inline.punctuation).replace(/punctuation/g, inline._punctuation).getRegex(); // sequences em should skip over [title](link), `code`, <html>
36571
36572         inline._blockSkip = '\\[[^\\]]*?\\]\\([^\\)]*?\\)|`[^`]*?`|<[^>]*?>';
36573         inline._overlapSkip = '__[^_]*?__|\\*\\*\\[^\\*\\]*?\\*\\*';
36574         inline._comment = edit$1(block._comment).replace('(?:-->|$)', '-->').getRegex();
36575         inline.em.start = edit$1(inline.em.start).replace(/punctuation/g, inline._punctuation).getRegex();
36576         inline.em.middle = edit$1(inline.em.middle).replace(/punctuation/g, inline._punctuation).replace(/overlapSkip/g, inline._overlapSkip).getRegex();
36577         inline.em.endAst = edit$1(inline.em.endAst, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36578         inline.em.endUnd = edit$1(inline.em.endUnd, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36579         inline.strong.start = edit$1(inline.strong.start).replace(/punctuation/g, inline._punctuation).getRegex();
36580         inline.strong.middle = edit$1(inline.strong.middle).replace(/punctuation/g, inline._punctuation).replace(/overlapSkip/g, inline._overlapSkip).getRegex();
36581         inline.strong.endAst = edit$1(inline.strong.endAst, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36582         inline.strong.endUnd = edit$1(inline.strong.endUnd, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36583         inline.blockSkip = edit$1(inline._blockSkip, 'g').getRegex();
36584         inline.overlapSkip = edit$1(inline._overlapSkip, 'g').getRegex();
36585         inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
36586         inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
36587         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])?)+(?![-_])/;
36588         inline.autolink = edit$1(inline.autolink).replace('scheme', inline._scheme).replace('email', inline._email).getRegex();
36589         inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
36590         inline.tag = edit$1(inline.tag).replace('comment', inline._comment).replace('attribute', inline._attribute).getRegex();
36591         inline._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
36592         inline._href = /<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/;
36593         inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
36594         inline.link = edit$1(inline.link).replace('label', inline._label).replace('href', inline._href).replace('title', inline._title).getRegex();
36595         inline.reflink = edit$1(inline.reflink).replace('label', inline._label).getRegex();
36596         inline.reflinkSearch = edit$1(inline.reflinkSearch, 'g').replace('reflink', inline.reflink).replace('nolink', inline.nolink).getRegex();
36597         /**
36598          * Normal Inline Grammar
36599          */
36600
36601         inline.normal = merge$2({}, inline);
36602         /**
36603          * Pedantic Inline Grammar
36604          */
36605
36606         inline.pedantic = merge$2({}, inline.normal, {
36607           strong: {
36608             start: /^__|\*\*/,
36609             middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
36610             endAst: /\*\*(?!\*)/g,
36611             endUnd: /__(?!_)/g
36612           },
36613           em: {
36614             start: /^_|\*/,
36615             middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
36616             endAst: /\*(?!\*)/g,
36617             endUnd: /_(?!_)/g
36618           },
36619           link: edit$1(/^!?\[(label)\]\((.*?)\)/).replace('label', inline._label).getRegex(),
36620           reflink: edit$1(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace('label', inline._label).getRegex()
36621         });
36622         /**
36623          * GFM Inline Grammar
36624          */
36625
36626         inline.gfm = merge$2({}, inline.normal, {
36627           escape: edit$1(inline.escape).replace('])', '~|])').getRegex(),
36628           _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
36629           url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
36630           _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
36631           del: /^~+(?=\S)([\s\S]*?\S)~+/,
36632           text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*~]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/
36633         });
36634         inline.gfm.url = edit$1(inline.gfm.url, 'i').replace('email', inline.gfm._extended_email).getRegex();
36635         /**
36636          * GFM + Line Breaks Inline Grammar
36637          */
36638
36639         inline.breaks = merge$2({}, inline.gfm, {
36640           br: edit$1(inline.br).replace('{2,}', '*').getRegex(),
36641           text: edit$1(inline.gfm.text).replace('\\b_', '\\b_| {2,}\\n').replace(/\{2,\}/g, '*').getRegex()
36642         });
36643         var rules = {
36644           block: block,
36645           inline: inline
36646         };
36647
36648         var defaults$2 = defaults.defaults;
36649         var block$1 = rules.block,
36650             inline$1 = rules.inline;
36651         var repeatString$1 = helpers.repeatString;
36652         /**
36653          * smartypants text replacement
36654          */
36655
36656         function smartypants(text) {
36657           return text // em-dashes
36658           .replace(/---/g, "\u2014") // en-dashes
36659           .replace(/--/g, "\u2013") // opening singles
36660           .replace(/(^|[-\u2014/(\[{"\s])'/g, "$1\u2018") // closing singles & apostrophes
36661           .replace(/'/g, "\u2019") // opening doubles
36662           .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, "$1\u201C") // closing doubles
36663           .replace(/"/g, "\u201D") // ellipses
36664           .replace(/\.{3}/g, "\u2026");
36665         }
36666         /**
36667          * mangle email addresses
36668          */
36669
36670
36671         function mangle(text) {
36672           var out = '',
36673               i,
36674               ch;
36675           var l = text.length;
36676
36677           for (i = 0; i < l; i++) {
36678             ch = text.charCodeAt(i);
36679
36680             if (Math.random() > 0.5) {
36681               ch = 'x' + ch.toString(16);
36682             }
36683
36684             out += '&#' + ch + ';';
36685           }
36686
36687           return out;
36688         }
36689         /**
36690          * Block Lexer
36691          */
36692
36693
36694         var Lexer_1 = /*#__PURE__*/function () {
36695           function Lexer(options) {
36696             _classCallCheck(this, Lexer);
36697
36698             this.tokens = [];
36699             this.tokens.links = Object.create(null);
36700             this.options = options || defaults$2;
36701             this.options.tokenizer = this.options.tokenizer || new Tokenizer_1();
36702             this.tokenizer = this.options.tokenizer;
36703             this.tokenizer.options = this.options;
36704             var rules = {
36705               block: block$1.normal,
36706               inline: inline$1.normal
36707             };
36708
36709             if (this.options.pedantic) {
36710               rules.block = block$1.pedantic;
36711               rules.inline = inline$1.pedantic;
36712             } else if (this.options.gfm) {
36713               rules.block = block$1.gfm;
36714
36715               if (this.options.breaks) {
36716                 rules.inline = inline$1.breaks;
36717               } else {
36718                 rules.inline = inline$1.gfm;
36719               }
36720             }
36721
36722             this.tokenizer.rules = rules;
36723           }
36724           /**
36725            * Expose Rules
36726            */
36727
36728
36729           _createClass(Lexer, [{
36730             key: "lex",
36731
36732             /**
36733              * Preprocessing
36734              */
36735             value: function lex(src) {
36736               src = src.replace(/\r\n|\r/g, '\n').replace(/\t/g, '    ');
36737               this.blockTokens(src, this.tokens, true);
36738               this.inline(this.tokens);
36739               return this.tokens;
36740             }
36741             /**
36742              * Lexing
36743              */
36744
36745           }, {
36746             key: "blockTokens",
36747             value: function blockTokens(src) {
36748               var tokens = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
36749               var top = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
36750               src = src.replace(/^ +$/gm, '');
36751               var token, i, l, lastToken;
36752
36753               while (src) {
36754                 // newline
36755                 if (token = this.tokenizer.space(src)) {
36756                   src = src.substring(token.raw.length);
36757
36758                   if (token.type) {
36759                     tokens.push(token);
36760                   }
36761
36762                   continue;
36763                 } // code
36764
36765
36766                 if (token = this.tokenizer.code(src, tokens)) {
36767                   src = src.substring(token.raw.length);
36768
36769                   if (token.type) {
36770                     tokens.push(token);
36771                   } else {
36772                     lastToken = tokens[tokens.length - 1];
36773                     lastToken.raw += '\n' + token.raw;
36774                     lastToken.text += '\n' + token.text;
36775                   }
36776
36777                   continue;
36778                 } // fences
36779
36780
36781                 if (token = this.tokenizer.fences(src)) {
36782                   src = src.substring(token.raw.length);
36783                   tokens.push(token);
36784                   continue;
36785                 } // heading
36786
36787
36788                 if (token = this.tokenizer.heading(src)) {
36789                   src = src.substring(token.raw.length);
36790                   tokens.push(token);
36791                   continue;
36792                 } // table no leading pipe (gfm)
36793
36794
36795                 if (token = this.tokenizer.nptable(src)) {
36796                   src = src.substring(token.raw.length);
36797                   tokens.push(token);
36798                   continue;
36799                 } // hr
36800
36801
36802                 if (token = this.tokenizer.hr(src)) {
36803                   src = src.substring(token.raw.length);
36804                   tokens.push(token);
36805                   continue;
36806                 } // blockquote
36807
36808
36809                 if (token = this.tokenizer.blockquote(src)) {
36810                   src = src.substring(token.raw.length);
36811                   token.tokens = this.blockTokens(token.text, [], top);
36812                   tokens.push(token);
36813                   continue;
36814                 } // list
36815
36816
36817                 if (token = this.tokenizer.list(src)) {
36818                   src = src.substring(token.raw.length);
36819                   l = token.items.length;
36820
36821                   for (i = 0; i < l; i++) {
36822                     token.items[i].tokens = this.blockTokens(token.items[i].text, [], false);
36823                   }
36824
36825                   tokens.push(token);
36826                   continue;
36827                 } // html
36828
36829
36830                 if (token = this.tokenizer.html(src)) {
36831                   src = src.substring(token.raw.length);
36832                   tokens.push(token);
36833                   continue;
36834                 } // def
36835
36836
36837                 if (top && (token = this.tokenizer.def(src))) {
36838                   src = src.substring(token.raw.length);
36839
36840                   if (!this.tokens.links[token.tag]) {
36841                     this.tokens.links[token.tag] = {
36842                       href: token.href,
36843                       title: token.title
36844                     };
36845                   }
36846
36847                   continue;
36848                 } // table (gfm)
36849
36850
36851                 if (token = this.tokenizer.table(src)) {
36852                   src = src.substring(token.raw.length);
36853                   tokens.push(token);
36854                   continue;
36855                 } // lheading
36856
36857
36858                 if (token = this.tokenizer.lheading(src)) {
36859                   src = src.substring(token.raw.length);
36860                   tokens.push(token);
36861                   continue;
36862                 } // top-level paragraph
36863
36864
36865                 if (top && (token = this.tokenizer.paragraph(src))) {
36866                   src = src.substring(token.raw.length);
36867                   tokens.push(token);
36868                   continue;
36869                 } // text
36870
36871
36872                 if (token = this.tokenizer.text(src, tokens)) {
36873                   src = src.substring(token.raw.length);
36874
36875                   if (token.type) {
36876                     tokens.push(token);
36877                   } else {
36878                     lastToken = tokens[tokens.length - 1];
36879                     lastToken.raw += '\n' + token.raw;
36880                     lastToken.text += '\n' + token.text;
36881                   }
36882
36883                   continue;
36884                 }
36885
36886                 if (src) {
36887                   var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
36888
36889                   if (this.options.silent) {
36890                     console.error(errMsg);
36891                     break;
36892                   } else {
36893                     throw new Error(errMsg);
36894                   }
36895                 }
36896               }
36897
36898               return tokens;
36899             }
36900           }, {
36901             key: "inline",
36902             value: function inline(tokens) {
36903               var i, j, k, l2, row, token;
36904               var l = tokens.length;
36905
36906               for (i = 0; i < l; i++) {
36907                 token = tokens[i];
36908
36909                 switch (token.type) {
36910                   case 'paragraph':
36911                   case 'text':
36912                   case 'heading':
36913                     {
36914                       token.tokens = [];
36915                       this.inlineTokens(token.text, token.tokens);
36916                       break;
36917                     }
36918
36919                   case 'table':
36920                     {
36921                       token.tokens = {
36922                         header: [],
36923                         cells: []
36924                       }; // header
36925
36926                       l2 = token.header.length;
36927
36928                       for (j = 0; j < l2; j++) {
36929                         token.tokens.header[j] = [];
36930                         this.inlineTokens(token.header[j], token.tokens.header[j]);
36931                       } // cells
36932
36933
36934                       l2 = token.cells.length;
36935
36936                       for (j = 0; j < l2; j++) {
36937                         row = token.cells[j];
36938                         token.tokens.cells[j] = [];
36939
36940                         for (k = 0; k < row.length; k++) {
36941                           token.tokens.cells[j][k] = [];
36942                           this.inlineTokens(row[k], token.tokens.cells[j][k]);
36943                         }
36944                       }
36945
36946                       break;
36947                     }
36948
36949                   case 'blockquote':
36950                     {
36951                       this.inline(token.tokens);
36952                       break;
36953                     }
36954
36955                   case 'list':
36956                     {
36957                       l2 = token.items.length;
36958
36959                       for (j = 0; j < l2; j++) {
36960                         this.inline(token.items[j].tokens);
36961                       }
36962
36963                       break;
36964                     }
36965                 }
36966               }
36967
36968               return tokens;
36969             }
36970             /**
36971              * Lexing/Compiling
36972              */
36973
36974           }, {
36975             key: "inlineTokens",
36976             value: function inlineTokens(src) {
36977               var tokens = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
36978               var inLink = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
36979               var inRawBlock = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
36980               var prevChar = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : '';
36981               var token; // String with links masked to avoid interference with em and strong
36982
36983               var maskedSrc = src;
36984               var match; // Mask out reflinks
36985
36986               if (this.tokens.links) {
36987                 var links = Object.keys(this.tokens.links);
36988
36989                 if (links.length > 0) {
36990                   while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {
36991                     if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {
36992                       maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString$1('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);
36993                     }
36994                   }
36995                 }
36996               } // Mask out other blocks
36997
36998
36999               while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {
37000                 maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString$1('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
37001               }
37002
37003               while (src) {
37004                 // escape
37005                 if (token = this.tokenizer.escape(src)) {
37006                   src = src.substring(token.raw.length);
37007                   tokens.push(token);
37008                   continue;
37009                 } // tag
37010
37011
37012                 if (token = this.tokenizer.tag(src, inLink, inRawBlock)) {
37013                   src = src.substring(token.raw.length);
37014                   inLink = token.inLink;
37015                   inRawBlock = token.inRawBlock;
37016                   tokens.push(token);
37017                   continue;
37018                 } // link
37019
37020
37021                 if (token = this.tokenizer.link(src)) {
37022                   src = src.substring(token.raw.length);
37023
37024                   if (token.type === 'link') {
37025                     token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
37026                   }
37027
37028                   tokens.push(token);
37029                   continue;
37030                 } // reflink, nolink
37031
37032
37033                 if (token = this.tokenizer.reflink(src, this.tokens.links)) {
37034                   src = src.substring(token.raw.length);
37035
37036                   if (token.type === 'link') {
37037                     token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
37038                   }
37039
37040                   tokens.push(token);
37041                   continue;
37042                 } // strong
37043
37044
37045                 if (token = this.tokenizer.strong(src, maskedSrc, prevChar)) {
37046                   src = src.substring(token.raw.length);
37047                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
37048                   tokens.push(token);
37049                   continue;
37050                 } // em
37051
37052
37053                 if (token = this.tokenizer.em(src, maskedSrc, prevChar)) {
37054                   src = src.substring(token.raw.length);
37055                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
37056                   tokens.push(token);
37057                   continue;
37058                 } // code
37059
37060
37061                 if (token = this.tokenizer.codespan(src)) {
37062                   src = src.substring(token.raw.length);
37063                   tokens.push(token);
37064                   continue;
37065                 } // br
37066
37067
37068                 if (token = this.tokenizer.br(src)) {
37069                   src = src.substring(token.raw.length);
37070                   tokens.push(token);
37071                   continue;
37072                 } // del (gfm)
37073
37074
37075                 if (token = this.tokenizer.del(src)) {
37076                   src = src.substring(token.raw.length);
37077                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
37078                   tokens.push(token);
37079                   continue;
37080                 } // autolink
37081
37082
37083                 if (token = this.tokenizer.autolink(src, mangle)) {
37084                   src = src.substring(token.raw.length);
37085                   tokens.push(token);
37086                   continue;
37087                 } // url (gfm)
37088
37089
37090                 if (!inLink && (token = this.tokenizer.url(src, mangle))) {
37091                   src = src.substring(token.raw.length);
37092                   tokens.push(token);
37093                   continue;
37094                 } // text
37095
37096
37097                 if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) {
37098                   src = src.substring(token.raw.length);
37099                   prevChar = token.raw.slice(-1);
37100                   tokens.push(token);
37101                   continue;
37102                 }
37103
37104                 if (src) {
37105                   var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
37106
37107                   if (this.options.silent) {
37108                     console.error(errMsg);
37109                     break;
37110                   } else {
37111                     throw new Error(errMsg);
37112                   }
37113                 }
37114               }
37115
37116               return tokens;
37117             }
37118           }], [{
37119             key: "lex",
37120
37121             /**
37122              * Static Lex Method
37123              */
37124             value: function lex(src, options) {
37125               var lexer = new Lexer(options);
37126               return lexer.lex(src);
37127             }
37128             /**
37129              * Static Lex Inline Method
37130              */
37131
37132           }, {
37133             key: "lexInline",
37134             value: function lexInline(src, options) {
37135               var lexer = new Lexer(options);
37136               return lexer.inlineTokens(src);
37137             }
37138           }, {
37139             key: "rules",
37140             get: function get() {
37141               return {
37142                 block: block$1,
37143                 inline: inline$1
37144               };
37145             }
37146           }]);
37147
37148           return Lexer;
37149         }();
37150
37151         var defaults$3 = defaults.defaults;
37152         var cleanUrl$1 = helpers.cleanUrl,
37153             escape$2 = helpers.escape;
37154         /**
37155          * Renderer
37156          */
37157
37158         var Renderer_1 = /*#__PURE__*/function () {
37159           function Renderer(options) {
37160             _classCallCheck(this, Renderer);
37161
37162             this.options = options || defaults$3;
37163           }
37164
37165           _createClass(Renderer, [{
37166             key: "code",
37167             value: function code(_code, infostring, escaped) {
37168               var lang = (infostring || '').match(/\S*/)[0];
37169
37170               if (this.options.highlight) {
37171                 var out = this.options.highlight(_code, lang);
37172
37173                 if (out != null && out !== _code) {
37174                   escaped = true;
37175                   _code = out;
37176                 }
37177               }
37178
37179               if (!lang) {
37180                 return '<pre><code>' + (escaped ? _code : escape$2(_code, true)) + '</code></pre>\n';
37181               }
37182
37183               return '<pre><code class="' + this.options.langPrefix + escape$2(lang, true) + '">' + (escaped ? _code : escape$2(_code, true)) + '</code></pre>\n';
37184             }
37185           }, {
37186             key: "blockquote",
37187             value: function blockquote(quote) {
37188               return '<blockquote>\n' + quote + '</blockquote>\n';
37189             }
37190           }, {
37191             key: "html",
37192             value: function html(_html) {
37193               return _html;
37194             }
37195           }, {
37196             key: "heading",
37197             value: function heading(text, level, raw, slugger) {
37198               if (this.options.headerIds) {
37199                 return '<h' + level + ' id="' + this.options.headerPrefix + slugger.slug(raw) + '">' + text + '</h' + level + '>\n';
37200               } // ignore IDs
37201
37202
37203               return '<h' + level + '>' + text + '</h' + level + '>\n';
37204             }
37205           }, {
37206             key: "hr",
37207             value: function hr() {
37208               return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
37209             }
37210           }, {
37211             key: "list",
37212             value: function list(body, ordered, start) {
37213               var type = ordered ? 'ol' : 'ul',
37214                   startatt = ordered && start !== 1 ? ' start="' + start + '"' : '';
37215               return '<' + type + startatt + '>\n' + body + '</' + type + '>\n';
37216             }
37217           }, {
37218             key: "listitem",
37219             value: function listitem(text) {
37220               return '<li>' + text + '</li>\n';
37221             }
37222           }, {
37223             key: "checkbox",
37224             value: function checkbox(checked) {
37225               return '<input ' + (checked ? 'checked="" ' : '') + 'disabled="" type="checkbox"' + (this.options.xhtml ? ' /' : '') + '> ';
37226             }
37227           }, {
37228             key: "paragraph",
37229             value: function paragraph(text) {
37230               return '<p>' + text + '</p>\n';
37231             }
37232           }, {
37233             key: "table",
37234             value: function table(header, body) {
37235               if (body) body = '<tbody>' + body + '</tbody>';
37236               return '<table>\n' + '<thead>\n' + header + '</thead>\n' + body + '</table>\n';
37237             }
37238           }, {
37239             key: "tablerow",
37240             value: function tablerow(content) {
37241               return '<tr>\n' + content + '</tr>\n';
37242             }
37243           }, {
37244             key: "tablecell",
37245             value: function tablecell(content, flags) {
37246               var type = flags.header ? 'th' : 'td';
37247               var tag = flags.align ? '<' + type + ' align="' + flags.align + '">' : '<' + type + '>';
37248               return tag + content + '</' + type + '>\n';
37249             } // span level renderer
37250
37251           }, {
37252             key: "strong",
37253             value: function strong(text) {
37254               return '<strong>' + text + '</strong>';
37255             }
37256           }, {
37257             key: "em",
37258             value: function em(text) {
37259               return '<em>' + text + '</em>';
37260             }
37261           }, {
37262             key: "codespan",
37263             value: function codespan(text) {
37264               return '<code>' + text + '</code>';
37265             }
37266           }, {
37267             key: "br",
37268             value: function br() {
37269               return this.options.xhtml ? '<br/>' : '<br>';
37270             }
37271           }, {
37272             key: "del",
37273             value: function del(text) {
37274               return '<del>' + text + '</del>';
37275             }
37276           }, {
37277             key: "link",
37278             value: function link(href, title, text) {
37279               href = cleanUrl$1(this.options.sanitize, this.options.baseUrl, href);
37280
37281               if (href === null) {
37282                 return text;
37283               }
37284
37285               var out = '<a href="' + escape$2(href) + '"';
37286
37287               if (title) {
37288                 out += ' title="' + title + '"';
37289               }
37290
37291               out += '>' + text + '</a>';
37292               return out;
37293             }
37294           }, {
37295             key: "image",
37296             value: function image(href, title, text) {
37297               href = cleanUrl$1(this.options.sanitize, this.options.baseUrl, href);
37298
37299               if (href === null) {
37300                 return text;
37301               }
37302
37303               var out = '<img src="' + href + '" alt="' + text + '"';
37304
37305               if (title) {
37306                 out += ' title="' + title + '"';
37307               }
37308
37309               out += this.options.xhtml ? '/>' : '>';
37310               return out;
37311             }
37312           }, {
37313             key: "text",
37314             value: function text(_text) {
37315               return _text;
37316             }
37317           }]);
37318
37319           return Renderer;
37320         }();
37321
37322         /**
37323          * TextRenderer
37324          * returns only the textual part of the token
37325          */
37326         var TextRenderer_1 = /*#__PURE__*/function () {
37327           function TextRenderer() {
37328             _classCallCheck(this, TextRenderer);
37329           }
37330
37331           _createClass(TextRenderer, [{
37332             key: "strong",
37333             // no need for block level renderers
37334             value: function strong(text) {
37335               return text;
37336             }
37337           }, {
37338             key: "em",
37339             value: function em(text) {
37340               return text;
37341             }
37342           }, {
37343             key: "codespan",
37344             value: function codespan(text) {
37345               return text;
37346             }
37347           }, {
37348             key: "del",
37349             value: function del(text) {
37350               return text;
37351             }
37352           }, {
37353             key: "html",
37354             value: function html(text) {
37355               return text;
37356             }
37357           }, {
37358             key: "text",
37359             value: function text(_text) {
37360               return _text;
37361             }
37362           }, {
37363             key: "link",
37364             value: function link(href, title, text) {
37365               return '' + text;
37366             }
37367           }, {
37368             key: "image",
37369             value: function image(href, title, text) {
37370               return '' + text;
37371             }
37372           }, {
37373             key: "br",
37374             value: function br() {
37375               return '';
37376             }
37377           }]);
37378
37379           return TextRenderer;
37380         }();
37381
37382         /**
37383          * Slugger generates header id
37384          */
37385         var Slugger_1 = /*#__PURE__*/function () {
37386           function Slugger() {
37387             _classCallCheck(this, Slugger);
37388
37389             this.seen = {};
37390           }
37391
37392           _createClass(Slugger, [{
37393             key: "serialize",
37394             value: function serialize(value) {
37395               return value.toLowerCase().trim() // remove html tags
37396               .replace(/<[!\/a-z].*?>/ig, '') // remove unwanted chars
37397               .replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, '').replace(/\s/g, '-');
37398             }
37399             /**
37400              * Finds the next safe (unique) slug to use
37401              */
37402
37403           }, {
37404             key: "getNextSafeSlug",
37405             value: function getNextSafeSlug(originalSlug, isDryRun) {
37406               var slug = originalSlug;
37407               var occurenceAccumulator = 0;
37408
37409               if (this.seen.hasOwnProperty(slug)) {
37410                 occurenceAccumulator = this.seen[originalSlug];
37411
37412                 do {
37413                   occurenceAccumulator++;
37414                   slug = originalSlug + '-' + occurenceAccumulator;
37415                 } while (this.seen.hasOwnProperty(slug));
37416               }
37417
37418               if (!isDryRun) {
37419                 this.seen[originalSlug] = occurenceAccumulator;
37420                 this.seen[slug] = 0;
37421               }
37422
37423               return slug;
37424             }
37425             /**
37426              * Convert string to unique id
37427              * @param {object} options
37428              * @param {boolean} options.dryrun Generates the next unique slug without updating the internal accumulator.
37429              */
37430
37431           }, {
37432             key: "slug",
37433             value: function slug(value) {
37434               var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
37435               var slug = this.serialize(value);
37436               return this.getNextSafeSlug(slug, options.dryrun);
37437             }
37438           }]);
37439
37440           return Slugger;
37441         }();
37442
37443         var defaults$4 = defaults.defaults;
37444         var unescape$2 = helpers.unescape;
37445         /**
37446          * Parsing & Compiling
37447          */
37448
37449         var Parser_1 = /*#__PURE__*/function () {
37450           function Parser(options) {
37451             _classCallCheck(this, Parser);
37452
37453             this.options = options || defaults$4;
37454             this.options.renderer = this.options.renderer || new Renderer_1();
37455             this.renderer = this.options.renderer;
37456             this.renderer.options = this.options;
37457             this.textRenderer = new TextRenderer_1();
37458             this.slugger = new Slugger_1();
37459           }
37460           /**
37461            * Static Parse Method
37462            */
37463
37464
37465           _createClass(Parser, [{
37466             key: "parse",
37467
37468             /**
37469              * Parse Loop
37470              */
37471             value: function parse(tokens) {
37472               var top = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
37473               var out = '',
37474                   i,
37475                   j,
37476                   k,
37477                   l2,
37478                   l3,
37479                   row,
37480                   cell,
37481                   header,
37482                   body,
37483                   token,
37484                   ordered,
37485                   start,
37486                   loose,
37487                   itemBody,
37488                   item,
37489                   checked,
37490                   task,
37491                   checkbox;
37492               var l = tokens.length;
37493
37494               for (i = 0; i < l; i++) {
37495                 token = tokens[i];
37496
37497                 switch (token.type) {
37498                   case 'space':
37499                     {
37500                       continue;
37501                     }
37502
37503                   case 'hr':
37504                     {
37505                       out += this.renderer.hr();
37506                       continue;
37507                     }
37508
37509                   case 'heading':
37510                     {
37511                       out += this.renderer.heading(this.parseInline(token.tokens), token.depth, unescape$2(this.parseInline(token.tokens, this.textRenderer)), this.slugger);
37512                       continue;
37513                     }
37514
37515                   case 'code':
37516                     {
37517                       out += this.renderer.code(token.text, token.lang, token.escaped);
37518                       continue;
37519                     }
37520
37521                   case 'table':
37522                     {
37523                       header = ''; // header
37524
37525                       cell = '';
37526                       l2 = token.header.length;
37527
37528                       for (j = 0; j < l2; j++) {
37529                         cell += this.renderer.tablecell(this.parseInline(token.tokens.header[j]), {
37530                           header: true,
37531                           align: token.align[j]
37532                         });
37533                       }
37534
37535                       header += this.renderer.tablerow(cell);
37536                       body = '';
37537                       l2 = token.cells.length;
37538
37539                       for (j = 0; j < l2; j++) {
37540                         row = token.tokens.cells[j];
37541                         cell = '';
37542                         l3 = row.length;
37543
37544                         for (k = 0; k < l3; k++) {
37545                           cell += this.renderer.tablecell(this.parseInline(row[k]), {
37546                             header: false,
37547                             align: token.align[k]
37548                           });
37549                         }
37550
37551                         body += this.renderer.tablerow(cell);
37552                       }
37553
37554                       out += this.renderer.table(header, body);
37555                       continue;
37556                     }
37557
37558                   case 'blockquote':
37559                     {
37560                       body = this.parse(token.tokens);
37561                       out += this.renderer.blockquote(body);
37562                       continue;
37563                     }
37564
37565                   case 'list':
37566                     {
37567                       ordered = token.ordered;
37568                       start = token.start;
37569                       loose = token.loose;
37570                       l2 = token.items.length;
37571                       body = '';
37572
37573                       for (j = 0; j < l2; j++) {
37574                         item = token.items[j];
37575                         checked = item.checked;
37576                         task = item.task;
37577                         itemBody = '';
37578
37579                         if (item.task) {
37580                           checkbox = this.renderer.checkbox(checked);
37581
37582                           if (loose) {
37583                             if (item.tokens.length > 0 && item.tokens[0].type === 'text') {
37584                               item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;
37585
37586                               if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {
37587                                 item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;
37588                               }
37589                             } else {
37590                               item.tokens.unshift({
37591                                 type: 'text',
37592                                 text: checkbox
37593                               });
37594                             }
37595                           } else {
37596                             itemBody += checkbox;
37597                           }
37598                         }
37599
37600                         itemBody += this.parse(item.tokens, loose);
37601                         body += this.renderer.listitem(itemBody, task, checked);
37602                       }
37603
37604                       out += this.renderer.list(body, ordered, start);
37605                       continue;
37606                     }
37607
37608                   case 'html':
37609                     {
37610                       // TODO parse inline content if parameter markdown=1
37611                       out += this.renderer.html(token.text);
37612                       continue;
37613                     }
37614
37615                   case 'paragraph':
37616                     {
37617                       out += this.renderer.paragraph(this.parseInline(token.tokens));
37618                       continue;
37619                     }
37620
37621                   case 'text':
37622                     {
37623                       body = token.tokens ? this.parseInline(token.tokens) : token.text;
37624
37625                       while (i + 1 < l && tokens[i + 1].type === 'text') {
37626                         token = tokens[++i];
37627                         body += '\n' + (token.tokens ? this.parseInline(token.tokens) : token.text);
37628                       }
37629
37630                       out += top ? this.renderer.paragraph(body) : body;
37631                       continue;
37632                     }
37633
37634                   default:
37635                     {
37636                       var errMsg = 'Token with "' + token.type + '" type was not found.';
37637
37638                       if (this.options.silent) {
37639                         console.error(errMsg);
37640                         return;
37641                       } else {
37642                         throw new Error(errMsg);
37643                       }
37644                     }
37645                 }
37646               }
37647
37648               return out;
37649             }
37650             /**
37651              * Parse Inline Tokens
37652              */
37653
37654           }, {
37655             key: "parseInline",
37656             value: function parseInline(tokens, renderer) {
37657               renderer = renderer || this.renderer;
37658               var out = '',
37659                   i,
37660                   token;
37661               var l = tokens.length;
37662
37663               for (i = 0; i < l; i++) {
37664                 token = tokens[i];
37665
37666                 switch (token.type) {
37667                   case 'escape':
37668                     {
37669                       out += renderer.text(token.text);
37670                       break;
37671                     }
37672
37673                   case 'html':
37674                     {
37675                       out += renderer.html(token.text);
37676                       break;
37677                     }
37678
37679                   case 'link':
37680                     {
37681                       out += renderer.link(token.href, token.title, this.parseInline(token.tokens, renderer));
37682                       break;
37683                     }
37684
37685                   case 'image':
37686                     {
37687                       out += renderer.image(token.href, token.title, token.text);
37688                       break;
37689                     }
37690
37691                   case 'strong':
37692                     {
37693                       out += renderer.strong(this.parseInline(token.tokens, renderer));
37694                       break;
37695                     }
37696
37697                   case 'em':
37698                     {
37699                       out += renderer.em(this.parseInline(token.tokens, renderer));
37700                       break;
37701                     }
37702
37703                   case 'codespan':
37704                     {
37705                       out += renderer.codespan(token.text);
37706                       break;
37707                     }
37708
37709                   case 'br':
37710                     {
37711                       out += renderer.br();
37712                       break;
37713                     }
37714
37715                   case 'del':
37716                     {
37717                       out += renderer.del(this.parseInline(token.tokens, renderer));
37718                       break;
37719                     }
37720
37721                   case 'text':
37722                     {
37723                       out += renderer.text(token.text);
37724                       break;
37725                     }
37726
37727                   default:
37728                     {
37729                       var errMsg = 'Token with "' + token.type + '" type was not found.';
37730
37731                       if (this.options.silent) {
37732                         console.error(errMsg);
37733                         return;
37734                       } else {
37735                         throw new Error(errMsg);
37736                       }
37737                     }
37738                 }
37739               }
37740
37741               return out;
37742             }
37743           }], [{
37744             key: "parse",
37745             value: function parse(tokens, options) {
37746               var parser = new Parser(options);
37747               return parser.parse(tokens);
37748             }
37749             /**
37750              * Static Parse Inline Method
37751              */
37752
37753           }, {
37754             key: "parseInline",
37755             value: function parseInline(tokens, options) {
37756               var parser = new Parser(options);
37757               return parser.parseInline(tokens);
37758             }
37759           }]);
37760
37761           return Parser;
37762         }();
37763
37764         var merge$3 = helpers.merge,
37765             checkSanitizeDeprecation$1 = helpers.checkSanitizeDeprecation,
37766             escape$3 = helpers.escape;
37767         var getDefaults = defaults.getDefaults,
37768             changeDefaults = defaults.changeDefaults,
37769             defaults$5 = defaults.defaults;
37770         /**
37771          * Marked
37772          */
37773
37774         function marked(src, opt, callback) {
37775           // throw error in case of non string input
37776           if (typeof src === 'undefined' || src === null) {
37777             throw new Error('marked(): input parameter is undefined or null');
37778           }
37779
37780           if (typeof src !== 'string') {
37781             throw new Error('marked(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');
37782           }
37783
37784           if (typeof opt === 'function') {
37785             callback = opt;
37786             opt = null;
37787           }
37788
37789           opt = merge$3({}, marked.defaults, opt || {});
37790           checkSanitizeDeprecation$1(opt);
37791
37792           if (callback) {
37793             var highlight = opt.highlight;
37794             var tokens;
37795
37796             try {
37797               tokens = Lexer_1.lex(src, opt);
37798             } catch (e) {
37799               return callback(e);
37800             }
37801
37802             var done = function done(err) {
37803               var out;
37804
37805               if (!err) {
37806                 try {
37807                   out = Parser_1.parse(tokens, opt);
37808                 } catch (e) {
37809                   err = e;
37810                 }
37811               }
37812
37813               opt.highlight = highlight;
37814               return err ? callback(err) : callback(null, out);
37815             };
37816
37817             if (!highlight || highlight.length < 3) {
37818               return done();
37819             }
37820
37821             delete opt.highlight;
37822             if (!tokens.length) return done();
37823             var pending = 0;
37824             marked.walkTokens(tokens, function (token) {
37825               if (token.type === 'code') {
37826                 pending++;
37827                 setTimeout(function () {
37828                   highlight(token.text, token.lang, function (err, code) {
37829                     if (err) {
37830                       return done(err);
37831                     }
37832
37833                     if (code != null && code !== token.text) {
37834                       token.text = code;
37835                       token.escaped = true;
37836                     }
37837
37838                     pending--;
37839
37840                     if (pending === 0) {
37841                       done();
37842                     }
37843                   });
37844                 }, 0);
37845               }
37846             });
37847
37848             if (pending === 0) {
37849               done();
37850             }
37851
37852             return;
37853           }
37854
37855           try {
37856             var _tokens = Lexer_1.lex(src, opt);
37857
37858             if (opt.walkTokens) {
37859               marked.walkTokens(_tokens, opt.walkTokens);
37860             }
37861
37862             return Parser_1.parse(_tokens, opt);
37863           } catch (e) {
37864             e.message += '\nPlease report this to https://github.com/markedjs/marked.';
37865
37866             if (opt.silent) {
37867               return '<p>An error occurred:</p><pre>' + escape$3(e.message + '', true) + '</pre>';
37868             }
37869
37870             throw e;
37871           }
37872         }
37873         /**
37874          * Options
37875          */
37876
37877
37878         marked.options = marked.setOptions = function (opt) {
37879           merge$3(marked.defaults, opt);
37880           changeDefaults(marked.defaults);
37881           return marked;
37882         };
37883
37884         marked.getDefaults = getDefaults;
37885         marked.defaults = defaults$5;
37886         /**
37887          * Use Extension
37888          */
37889
37890         marked.use = function (extension) {
37891           var opts = merge$3({}, extension);
37892
37893           if (extension.renderer) {
37894             (function () {
37895               var renderer = marked.defaults.renderer || new Renderer_1();
37896
37897               var _loop = function _loop(prop) {
37898                 var prevRenderer = renderer[prop];
37899
37900                 renderer[prop] = function () {
37901                   for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
37902                     args[_key] = arguments[_key];
37903                   }
37904
37905                   var ret = extension.renderer[prop].apply(renderer, args);
37906
37907                   if (ret === false) {
37908                     ret = prevRenderer.apply(renderer, args);
37909                   }
37910
37911                   return ret;
37912                 };
37913               };
37914
37915               for (var prop in extension.renderer) {
37916                 _loop(prop);
37917               }
37918
37919               opts.renderer = renderer;
37920             })();
37921           }
37922
37923           if (extension.tokenizer) {
37924             (function () {
37925               var tokenizer = marked.defaults.tokenizer || new Tokenizer_1();
37926
37927               var _loop2 = function _loop2(prop) {
37928                 var prevTokenizer = tokenizer[prop];
37929
37930                 tokenizer[prop] = function () {
37931                   for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
37932                     args[_key2] = arguments[_key2];
37933                   }
37934
37935                   var ret = extension.tokenizer[prop].apply(tokenizer, args);
37936
37937                   if (ret === false) {
37938                     ret = prevTokenizer.apply(tokenizer, args);
37939                   }
37940
37941                   return ret;
37942                 };
37943               };
37944
37945               for (var prop in extension.tokenizer) {
37946                 _loop2(prop);
37947               }
37948
37949               opts.tokenizer = tokenizer;
37950             })();
37951           }
37952
37953           if (extension.walkTokens) {
37954             var walkTokens = marked.defaults.walkTokens;
37955
37956             opts.walkTokens = function (token) {
37957               extension.walkTokens(token);
37958
37959               if (walkTokens) {
37960                 walkTokens(token);
37961               }
37962             };
37963           }
37964
37965           marked.setOptions(opts);
37966         };
37967         /**
37968          * Run callback for every token
37969          */
37970
37971
37972         marked.walkTokens = function (tokens, callback) {
37973           var _iterator = _createForOfIteratorHelper(tokens),
37974               _step;
37975
37976           try {
37977             for (_iterator.s(); !(_step = _iterator.n()).done;) {
37978               var token = _step.value;
37979               callback(token);
37980
37981               switch (token.type) {
37982                 case 'table':
37983                   {
37984                     var _iterator2 = _createForOfIteratorHelper(token.tokens.header),
37985                         _step2;
37986
37987                     try {
37988                       for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
37989                         var cell = _step2.value;
37990                         marked.walkTokens(cell, callback);
37991                       }
37992                     } catch (err) {
37993                       _iterator2.e(err);
37994                     } finally {
37995                       _iterator2.f();
37996                     }
37997
37998                     var _iterator3 = _createForOfIteratorHelper(token.tokens.cells),
37999                         _step3;
38000
38001                     try {
38002                       for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
38003                         var row = _step3.value;
38004
38005                         var _iterator4 = _createForOfIteratorHelper(row),
38006                             _step4;
38007
38008                         try {
38009                           for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
38010                             var _cell = _step4.value;
38011                             marked.walkTokens(_cell, callback);
38012                           }
38013                         } catch (err) {
38014                           _iterator4.e(err);
38015                         } finally {
38016                           _iterator4.f();
38017                         }
38018                       }
38019                     } catch (err) {
38020                       _iterator3.e(err);
38021                     } finally {
38022                       _iterator3.f();
38023                     }
38024
38025                     break;
38026                   }
38027
38028                 case 'list':
38029                   {
38030                     marked.walkTokens(token.items, callback);
38031                     break;
38032                   }
38033
38034                 default:
38035                   {
38036                     if (token.tokens) {
38037                       marked.walkTokens(token.tokens, callback);
38038                     }
38039                   }
38040               }
38041             }
38042           } catch (err) {
38043             _iterator.e(err);
38044           } finally {
38045             _iterator.f();
38046           }
38047         };
38048         /**
38049          * Parse Inline
38050          */
38051
38052
38053         marked.parseInline = function (src, opt) {
38054           // throw error in case of non string input
38055           if (typeof src === 'undefined' || src === null) {
38056             throw new Error('marked.parseInline(): input parameter is undefined or null');
38057           }
38058
38059           if (typeof src !== 'string') {
38060             throw new Error('marked.parseInline(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');
38061           }
38062
38063           opt = merge$3({}, marked.defaults, opt || {});
38064           checkSanitizeDeprecation$1(opt);
38065
38066           try {
38067             var tokens = Lexer_1.lexInline(src, opt);
38068
38069             if (opt.walkTokens) {
38070               marked.walkTokens(tokens, opt.walkTokens);
38071             }
38072
38073             return Parser_1.parseInline(tokens, opt);
38074           } catch (e) {
38075             e.message += '\nPlease report this to https://github.com/markedjs/marked.';
38076
38077             if (opt.silent) {
38078               return '<p>An error occurred:</p><pre>' + escape$3(e.message + '', true) + '</pre>';
38079             }
38080
38081             throw e;
38082           }
38083         };
38084         /**
38085          * Expose
38086          */
38087
38088
38089         marked.Parser = Parser_1;
38090         marked.parser = Parser_1.parse;
38091         marked.Renderer = Renderer_1;
38092         marked.TextRenderer = TextRenderer_1;
38093         marked.Lexer = Lexer_1;
38094         marked.lexer = Lexer_1.lex;
38095         marked.Tokenizer = Tokenizer_1;
38096         marked.Slugger = Slugger_1;
38097         marked.parse = marked;
38098         var marked_1 = marked;
38099
38100         var tiler$2 = utilTiler();
38101         var dispatch$3 = dispatch('loaded');
38102         var _tileZoom$2 = 14;
38103         var _osmoseUrlRoot = 'https://osmose.openstreetmap.fr/api/0.3';
38104         var _osmoseData = {
38105           icons: {},
38106           items: []
38107         }; // This gets reassigned if reset
38108
38109         var _cache$2;
38110
38111         function abortRequest$2(controller) {
38112           if (controller) {
38113             controller.abort();
38114           }
38115         }
38116
38117         function abortUnwantedRequests$2(cache, tiles) {
38118           Object.keys(cache.inflightTile).forEach(function (k) {
38119             var wanted = tiles.find(function (tile) {
38120               return k === tile.id;
38121             });
38122
38123             if (!wanted) {
38124               abortRequest$2(cache.inflightTile[k]);
38125               delete cache.inflightTile[k];
38126             }
38127           });
38128         }
38129
38130         function encodeIssueRtree$2(d) {
38131           return {
38132             minX: d.loc[0],
38133             minY: d.loc[1],
38134             maxX: d.loc[0],
38135             maxY: d.loc[1],
38136             data: d
38137           };
38138         } // Replace or remove QAItem from rtree
38139
38140
38141         function updateRtree$2(item, replace) {
38142           _cache$2.rtree.remove(item, function (a, b) {
38143             return a.data.id === b.data.id;
38144           });
38145
38146           if (replace) {
38147             _cache$2.rtree.insert(item);
38148           }
38149         } // Issues shouldn't obscure each other
38150
38151
38152         function preventCoincident$1(loc) {
38153           var coincident = false;
38154
38155           do {
38156             // first time, move marker up. after that, move marker right.
38157             var delta = coincident ? [0.00001, 0] : [0, 0.00001];
38158             loc = geoVecAdd(loc, delta);
38159             var bbox = geoExtent(loc).bbox();
38160             coincident = _cache$2.rtree.search(bbox).length;
38161           } while (coincident);
38162
38163           return loc;
38164         }
38165
38166         var serviceOsmose = {
38167           title: 'osmose',
38168           init: function init() {
38169             _mainFileFetcher.get('qa_data').then(function (d) {
38170               _osmoseData = d.osmose;
38171               _osmoseData.items = Object.keys(d.osmose.icons).map(function (s) {
38172                 return s.split('-')[0];
38173               }).reduce(function (unique, item) {
38174                 return unique.indexOf(item) !== -1 ? unique : [].concat(_toConsumableArray(unique), [item]);
38175               }, []);
38176             });
38177
38178             if (!_cache$2) {
38179               this.reset();
38180             }
38181
38182             this.event = utilRebind(this, dispatch$3, 'on');
38183           },
38184           reset: function reset() {
38185             var _strings = {};
38186             var _colors = {};
38187
38188             if (_cache$2) {
38189               Object.values(_cache$2.inflightTile).forEach(abortRequest$2); // Strings and colors are static and should not be re-populated
38190
38191               _strings = _cache$2.strings;
38192               _colors = _cache$2.colors;
38193             }
38194
38195             _cache$2 = {
38196               data: {},
38197               loadedTile: {},
38198               inflightTile: {},
38199               inflightPost: {},
38200               closed: {},
38201               rtree: new RBush(),
38202               strings: _strings,
38203               colors: _colors
38204             };
38205           },
38206           loadIssues: function loadIssues(projection) {
38207             var _this = this;
38208
38209             var params = {
38210               // Tiles return a maximum # of issues
38211               // So we want to filter our request for only types iD supports
38212               item: _osmoseData.items
38213             }; // determine the needed tiles to cover the view
38214
38215             var tiles = tiler$2.zoomExtent([_tileZoom$2, _tileZoom$2]).getTiles(projection); // abort inflight requests that are no longer needed
38216
38217             abortUnwantedRequests$2(_cache$2, tiles); // issue new requests..
38218
38219             tiles.forEach(function (tile) {
38220               if (_cache$2.loadedTile[tile.id] || _cache$2.inflightTile[tile.id]) return;
38221
38222               var _tile$xyz = _slicedToArray(tile.xyz, 3),
38223                   x = _tile$xyz[0],
38224                   y = _tile$xyz[1],
38225                   z = _tile$xyz[2];
38226
38227               var url = "".concat(_osmoseUrlRoot, "/issues/").concat(z, "/").concat(x, "/").concat(y, ".json?") + utilQsString(params);
38228               var controller = new AbortController();
38229               _cache$2.inflightTile[tile.id] = controller;
38230               d3_json(url, {
38231                 signal: controller.signal
38232               }).then(function (data) {
38233                 delete _cache$2.inflightTile[tile.id];
38234                 _cache$2.loadedTile[tile.id] = true;
38235
38236                 if (data.features) {
38237                   data.features.forEach(function (issue) {
38238                     var _issue$properties = issue.properties,
38239                         item = _issue$properties.item,
38240                         cl = _issue$properties["class"],
38241                         id = _issue$properties.uuid;
38242                     /* Osmose issues are uniquely identified by a unique
38243                       `item` and `class` combination (both integer values) */
38244
38245                     var itemType = "".concat(item, "-").concat(cl); // Filter out unsupported issue types (some are too specific or advanced)
38246
38247                     if (itemType in _osmoseData.icons) {
38248                       var loc = issue.geometry.coordinates; // lon, lat
38249
38250                       loc = preventCoincident$1(loc);
38251                       var d = new QAItem(loc, _this, itemType, id, {
38252                         item: item
38253                       }); // Setting elems here prevents UI detail requests
38254
38255                       if (item === 8300 || item === 8360) {
38256                         d.elems = [];
38257                       }
38258
38259                       _cache$2.data[d.id] = d;
38260
38261                       _cache$2.rtree.insert(encodeIssueRtree$2(d));
38262                     }
38263                   });
38264                 }
38265
38266                 dispatch$3.call('loaded');
38267               })["catch"](function () {
38268                 delete _cache$2.inflightTile[tile.id];
38269                 _cache$2.loadedTile[tile.id] = true;
38270               });
38271             });
38272           },
38273           loadIssueDetail: function loadIssueDetail(issue) {
38274             var _this2 = this;
38275
38276             // Issue details only need to be fetched once
38277             if (issue.elems !== undefined) {
38278               return Promise.resolve(issue);
38279             }
38280
38281             var url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "?langs=").concat(_mainLocalizer.localeCode());
38282
38283             var cacheDetails = function cacheDetails(data) {
38284               // Associated elements used for highlighting
38285               // Assign directly for immediate use in the callback
38286               issue.elems = data.elems.map(function (e) {
38287                 return e.type.substring(0, 1) + e.id;
38288               }); // Some issues have instance specific detail in a subtitle
38289
38290               issue.detail = data.subtitle ? marked_1(data.subtitle.auto) : '';
38291
38292               _this2.replaceItem(issue);
38293             };
38294
38295             return d3_json(url).then(cacheDetails).then(function () {
38296               return issue;
38297             });
38298           },
38299           loadStrings: function loadStrings() {
38300             var locale = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _mainLocalizer.localeCode();
38301             var items = Object.keys(_osmoseData.icons);
38302
38303             if (locale in _cache$2.strings && Object.keys(_cache$2.strings[locale]).length === items.length) {
38304               return Promise.resolve(_cache$2.strings[locale]);
38305             } // May be partially populated already if some requests were successful
38306
38307
38308             if (!(locale in _cache$2.strings)) {
38309               _cache$2.strings[locale] = {};
38310             } // Only need to cache strings for supported issue types
38311             // Using multiple individual item + class requests to reduce fetched data size
38312
38313
38314             var allRequests = items.map(function (itemType) {
38315               // No need to request data we already have
38316               if (itemType in _cache$2.strings[locale]) return null;
38317
38318               var cacheData = function cacheData(data) {
38319                 // Bunch of nested single value arrays of objects
38320                 var _data$categories = _slicedToArray(data.categories, 1),
38321                     _data$categories$ = _data$categories[0],
38322                     cat = _data$categories$ === void 0 ? {
38323                   items: []
38324                 } : _data$categories$;
38325
38326                 var _cat$items = _slicedToArray(cat.items, 1),
38327                     _cat$items$ = _cat$items[0],
38328                     item = _cat$items$ === void 0 ? {
38329                   "class": []
38330                 } : _cat$items$;
38331
38332                 var _item$class = _slicedToArray(item["class"], 1),
38333                     _item$class$ = _item$class[0],
38334                     cl = _item$class$ === void 0 ? null : _item$class$; // If null default value is reached, data wasn't as expected (or was empty)
38335
38336
38337                 if (!cl) {
38338                   /* eslint-disable no-console */
38339                   console.log("Osmose strings request (".concat(itemType, ") had unexpected data"));
38340                   /* eslint-enable no-console */
38341
38342                   return;
38343                 } // Cache served item colors to automatically style issue markers later
38344
38345
38346                 var itemInt = item.item,
38347                     color = item.color;
38348
38349                 if (/^#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/.test(color)) {
38350                   _cache$2.colors[itemInt] = color;
38351                 } // Value of root key will be null if no string exists
38352                 // If string exists, value is an object with key 'auto' for string
38353
38354
38355                 var title = cl.title,
38356                     detail = cl.detail,
38357                     fix = cl.fix,
38358                     trap = cl.trap; // Osmose titles shouldn't contain markdown
38359
38360                 var issueStrings = {};
38361                 if (title) issueStrings.title = title.auto;
38362                 if (detail) issueStrings.detail = marked_1(detail.auto);
38363                 if (trap) issueStrings.trap = marked_1(trap.auto);
38364                 if (fix) issueStrings.fix = marked_1(fix.auto);
38365                 _cache$2.strings[locale][itemType] = issueStrings;
38366               };
38367
38368               var _itemType$split = itemType.split('-'),
38369                   _itemType$split2 = _slicedToArray(_itemType$split, 2),
38370                   item = _itemType$split2[0],
38371                   cl = _itemType$split2[1]; // Osmose API falls back to English strings where untranslated or if locale doesn't exist
38372
38373
38374               var url = "".concat(_osmoseUrlRoot, "/items/").concat(item, "/class/").concat(cl, "?langs=").concat(locale);
38375               return d3_json(url).then(cacheData);
38376             }).filter(Boolean);
38377             return Promise.all(allRequests).then(function () {
38378               return _cache$2.strings[locale];
38379             });
38380           },
38381           getStrings: function getStrings(itemType) {
38382             var locale = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _mainLocalizer.localeCode();
38383             // No need to fallback to English, Osmose API handles this for us
38384             return locale in _cache$2.strings ? _cache$2.strings[locale][itemType] : {};
38385           },
38386           getColor: function getColor(itemType) {
38387             return itemType in _cache$2.colors ? _cache$2.colors[itemType] : '#FFFFFF';
38388           },
38389           postUpdate: function postUpdate(issue, callback) {
38390             var _this3 = this;
38391
38392             if (_cache$2.inflightPost[issue.id]) {
38393               return callback({
38394                 message: 'Issue update already inflight',
38395                 status: -2
38396               }, issue);
38397             } // UI sets the status to either 'done' or 'false'
38398
38399
38400             var url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "/").concat(issue.newStatus);
38401             var controller = new AbortController();
38402
38403             var after = function after() {
38404               delete _cache$2.inflightPost[issue.id];
38405
38406               _this3.removeItem(issue);
38407
38408               if (issue.newStatus === 'done') {
38409                 // Keep track of the number of issues closed per `item` to tag the changeset
38410                 if (!(issue.item in _cache$2.closed)) {
38411                   _cache$2.closed[issue.item] = 0;
38412                 }
38413
38414                 _cache$2.closed[issue.item] += 1;
38415               }
38416
38417               if (callback) callback(null, issue);
38418             };
38419
38420             _cache$2.inflightPost[issue.id] = controller;
38421             fetch(url, {
38422               signal: controller.signal
38423             }).then(after)["catch"](function (err) {
38424               delete _cache$2.inflightPost[issue.id];
38425               if (callback) callback(err.message);
38426             });
38427           },
38428           // Get all cached QAItems covering the viewport
38429           getItems: function getItems(projection) {
38430             var viewport = projection.clipExtent();
38431             var min = [viewport[0][0], viewport[1][1]];
38432             var max = [viewport[1][0], viewport[0][1]];
38433             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
38434             return _cache$2.rtree.search(bbox).map(function (d) {
38435               return d.data;
38436             });
38437           },
38438           // Get a QAItem from cache
38439           // NOTE: Don't change method name until UI v3 is merged
38440           getError: function getError(id) {
38441             return _cache$2.data[id];
38442           },
38443           // get the name of the icon to display for this item
38444           getIcon: function getIcon(itemType) {
38445             return _osmoseData.icons[itemType];
38446           },
38447           // Replace a single QAItem in the cache
38448           replaceItem: function replaceItem(item) {
38449             if (!(item instanceof QAItem) || !item.id) return;
38450             _cache$2.data[item.id] = item;
38451             updateRtree$2(encodeIssueRtree$2(item), true); // true = replace
38452
38453             return item;
38454           },
38455           // Remove a single QAItem from the cache
38456           removeItem: function removeItem(item) {
38457             if (!(item instanceof QAItem) || !item.id) return;
38458             delete _cache$2.data[item.id];
38459             updateRtree$2(encodeIssueRtree$2(item), false); // false = remove
38460           },
38461           // Used to populate `closed:osmose:*` changeset tags
38462           getClosedCounts: function getClosedCounts() {
38463             return _cache$2.closed;
38464           },
38465           itemURL: function itemURL(item) {
38466             return "https://osmose.openstreetmap.fr/en/error/".concat(item.id);
38467           }
38468         };
38469
38470         var apibase = 'https://a.mapillary.com/v3/';
38471         var viewercss = 'mapillary-js/mapillary.min.css';
38472         var viewerjs = 'mapillary-js/mapillary.min.js';
38473         var clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi';
38474         var mapFeatureConfig = {
38475           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(',')
38476         };
38477         var maxResults = 1000;
38478         var tileZoom = 14;
38479         var tiler$3 = utilTiler().zoomExtent([tileZoom, tileZoom]).skipNullIsland(true);
38480         var dispatch$4 = dispatch('change', 'loadedImages', 'loadedSigns', 'loadedMapFeatures', 'bearingChanged', 'nodeChanged');
38481         var _mlyFallback = false;
38482
38483         var _mlyCache;
38484
38485         var _mlyClicks;
38486
38487         var _mlyActiveImage;
38488
38489         var _mlySelectedImageKey;
38490
38491         var _mlyViewer;
38492
38493         var _mlyViewerFilter = ['all'];
38494
38495         var _loadViewerPromise;
38496
38497         var _mlyHighlightedDetection;
38498
38499         var _mlyShowFeatureDetections = false;
38500         var _mlyShowSignDetections = false;
38501
38502         function abortRequest$3(controller) {
38503           controller.abort();
38504         }
38505
38506         function loadTiles(which, url, projection) {
38507           var currZoom = Math.floor(geoScaleToZoom(projection.scale()));
38508           var tiles = tiler$3.getTiles(projection); // abort inflight requests that are no longer needed
38509
38510           var cache = _mlyCache[which];
38511           Object.keys(cache.inflight).forEach(function (k) {
38512             var wanted = tiles.find(function (tile) {
38513               return k.indexOf(tile.id + ',') === 0;
38514             });
38515
38516             if (!wanted) {
38517               abortRequest$3(cache.inflight[k]);
38518               delete cache.inflight[k];
38519             }
38520           });
38521           tiles.forEach(function (tile) {
38522             loadNextTilePage(which, currZoom, url, tile);
38523           });
38524         }
38525
38526         function loadNextTilePage(which, currZoom, url, tile) {
38527           var cache = _mlyCache[which];
38528           var rect = tile.extent.rectangle();
38529           var maxPages = maxPageAtZoom(currZoom);
38530           var nextPage = cache.nextPage[tile.id] || 0;
38531           var nextURL = cache.nextURL[tile.id] || url + utilQsString({
38532             per_page: maxResults,
38533             page: nextPage,
38534             client_id: clientId,
38535             bbox: [rect[0], rect[1], rect[2], rect[3]].join(',')
38536           });
38537           if (nextPage > maxPages) return;
38538           var id = tile.id + ',' + String(nextPage);
38539           if (cache.loaded[id] || cache.inflight[id]) return;
38540           var controller = new AbortController();
38541           cache.inflight[id] = controller;
38542           var options = {
38543             method: 'GET',
38544             signal: controller.signal,
38545             headers: {
38546               'Content-Type': 'application/json'
38547             }
38548           };
38549           fetch(nextURL, options).then(function (response) {
38550             if (!response.ok) {
38551               throw new Error(response.status + ' ' + response.statusText);
38552             }
38553
38554             var linkHeader = response.headers.get('Link');
38555
38556             if (linkHeader) {
38557               var pagination = parsePagination(linkHeader);
38558
38559               if (pagination.next) {
38560                 cache.nextURL[tile.id] = pagination.next;
38561               }
38562             }
38563
38564             return response.json();
38565           }).then(function (data) {
38566             cache.loaded[id] = true;
38567             delete cache.inflight[id];
38568
38569             if (!data || !data.features || !data.features.length) {
38570               throw new Error('No Data');
38571             }
38572
38573             var features = data.features.map(function (feature) {
38574               var loc = feature.geometry.coordinates;
38575               var d; // An image (shown as a green dot on the map) is a single street photo with extra
38576               // information such as location, camera angle (CA), camera model, and so on.
38577               // Each image feature is a GeoJSON Point
38578
38579               if (which === 'images') {
38580                 d = {
38581                   loc: loc,
38582                   key: feature.properties.key,
38583                   ca: feature.properties.ca,
38584                   captured_at: feature.properties.captured_at,
38585                   captured_by: feature.properties.username,
38586                   pano: feature.properties.pano
38587                 };
38588                 cache.forImageKey[d.key] = d; // cache imageKey -> image
38589                 // Mapillary organizes images as sequences. A sequence of images are continuously captured
38590                 // by a user at a give time. Sequences are shown on the map as green lines.
38591                 // Each sequence feature is a GeoJSON LineString
38592               } else if (which === 'sequences') {
38593                 var sequenceKey = feature.properties.key;
38594                 cache.lineString[sequenceKey] = feature; // cache sequenceKey -> lineString
38595
38596                 feature.properties.coordinateProperties.image_keys.forEach(function (imageKey) {
38597                   cache.forImageKey[imageKey] = sequenceKey; // cache imageKey -> sequenceKey
38598                 });
38599                 return false; // because no `d` data worth loading into an rbush
38600                 // A map feature is a real world object that can be shown on a map. It could be any object
38601                 // recognized from images, manually added in images, or added on the map.
38602                 // Each map feature is a GeoJSON Point (located where the feature is)
38603               } else if (which === 'map_features' || which === 'points') {
38604                 d = {
38605                   loc: loc,
38606                   key: feature.properties.key,
38607                   value: feature.properties.value,
38608                   detections: feature.properties.detections,
38609                   direction: feature.properties.direction,
38610                   accuracy: feature.properties.accuracy,
38611                   first_seen_at: feature.properties.first_seen_at,
38612                   last_seen_at: feature.properties.last_seen_at
38613                 };
38614               }
38615
38616               return {
38617                 minX: loc[0],
38618                 minY: loc[1],
38619                 maxX: loc[0],
38620                 maxY: loc[1],
38621                 data: d
38622               };
38623             }).filter(Boolean);
38624
38625             if (cache.rtree && features) {
38626               cache.rtree.load(features);
38627             }
38628
38629             if (data.features.length === maxResults) {
38630               // more pages to load
38631               cache.nextPage[tile.id] = nextPage + 1;
38632               loadNextTilePage(which, currZoom, url, tile);
38633             } else {
38634               cache.nextPage[tile.id] = Infinity; // no more pages to load
38635             }
38636
38637             if (which === 'images' || which === 'sequences') {
38638               dispatch$4.call('loadedImages');
38639             } else if (which === 'map_features') {
38640               dispatch$4.call('loadedSigns');
38641             } else if (which === 'points') {
38642               dispatch$4.call('loadedMapFeatures');
38643             }
38644           })["catch"](function () {
38645             cache.loaded[id] = true;
38646             delete cache.inflight[id];
38647           });
38648         }
38649
38650         function loadData(which, url) {
38651           var cache = _mlyCache[which];
38652           var options = {
38653             method: 'GET',
38654             headers: {
38655               'Content-Type': 'application/json'
38656             }
38657           };
38658           var nextUrl = url + '&client_id=' + clientId;
38659           return fetch(nextUrl, options).then(function (response) {
38660             if (!response.ok) {
38661               throw new Error(response.status + ' ' + response.statusText);
38662             }
38663
38664             return response.json();
38665           }).then(function (data) {
38666             if (!data || !data.features || !data.features.length) {
38667               throw new Error('No Data');
38668             }
38669
38670             data.features.forEach(function (feature) {
38671               var d;
38672
38673               if (which === 'image_detections') {
38674                 d = {
38675                   key: feature.properties.key,
38676                   image_key: feature.properties.image_key,
38677                   value: feature.properties.value,
38678                   shape: feature.properties.shape
38679                 };
38680
38681                 if (!cache.forImageKey[d.image_key]) {
38682                   cache.forImageKey[d.image_key] = [];
38683                 }
38684
38685                 cache.forImageKey[d.image_key].push(d);
38686               }
38687             });
38688           });
38689         }
38690
38691         function maxPageAtZoom(z) {
38692           if (z < 15) return 2;
38693           if (z === 15) return 5;
38694           if (z === 16) return 10;
38695           if (z === 17) return 20;
38696           if (z === 18) return 40;
38697           if (z > 18) return 80;
38698         } // extract links to pages of API results
38699
38700
38701         function parsePagination(links) {
38702           return links.split(',').map(function (rel) {
38703             var elements = rel.split(';');
38704
38705             if (elements.length === 2) {
38706               return [/<(.+)>/.exec(elements[0])[1], /rel="(.+)"/.exec(elements[1])[1]];
38707             } else {
38708               return ['', ''];
38709             }
38710           }).reduce(function (pagination, val) {
38711             pagination[val[1]] = val[0];
38712             return pagination;
38713           }, {});
38714         } // partition viewport into higher zoom tiles
38715
38716
38717         function partitionViewport(projection) {
38718           var z = geoScaleToZoom(projection.scale());
38719           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
38720
38721           var tiler = utilTiler().zoomExtent([z2, z2]);
38722           return tiler.getTiles(projection).map(function (tile) {
38723             return tile.extent;
38724           });
38725         } // no more than `limit` results per partition.
38726
38727
38728         function searchLimited(limit, projection, rtree) {
38729           limit = limit || 5;
38730           return partitionViewport(projection).reduce(function (result, extent) {
38731             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
38732               return d.data;
38733             });
38734             return found.length ? result.concat(found) : result;
38735           }, []);
38736         }
38737
38738         var serviceMapillary = {
38739           init: function init() {
38740             if (!_mlyCache) {
38741               this.reset();
38742             }
38743
38744             this.event = utilRebind(this, dispatch$4, 'on');
38745           },
38746           reset: function reset() {
38747             if (_mlyCache) {
38748               Object.values(_mlyCache.images.inflight).forEach(abortRequest$3);
38749               Object.values(_mlyCache.image_detections.inflight).forEach(abortRequest$3);
38750               Object.values(_mlyCache.map_features.inflight).forEach(abortRequest$3);
38751               Object.values(_mlyCache.points.inflight).forEach(abortRequest$3);
38752               Object.values(_mlyCache.sequences.inflight).forEach(abortRequest$3);
38753             }
38754
38755             _mlyCache = {
38756               images: {
38757                 inflight: {},
38758                 loaded: {},
38759                 nextPage: {},
38760                 nextURL: {},
38761                 rtree: new RBush(),
38762                 forImageKey: {}
38763               },
38764               image_detections: {
38765                 inflight: {},
38766                 loaded: {},
38767                 nextPage: {},
38768                 nextURL: {},
38769                 forImageKey: {}
38770               },
38771               map_features: {
38772                 inflight: {},
38773                 loaded: {},
38774                 nextPage: {},
38775                 nextURL: {},
38776                 rtree: new RBush()
38777               },
38778               points: {
38779                 inflight: {},
38780                 loaded: {},
38781                 nextPage: {},
38782                 nextURL: {},
38783                 rtree: new RBush()
38784               },
38785               sequences: {
38786                 inflight: {},
38787                 loaded: {},
38788                 nextPage: {},
38789                 nextURL: {},
38790                 rtree: new RBush(),
38791                 forImageKey: {},
38792                 lineString: {}
38793               }
38794             };
38795             _mlySelectedImageKey = null;
38796             _mlyActiveImage = null;
38797             _mlyClicks = [];
38798           },
38799           images: function images(projection) {
38800             var limit = 5;
38801             return searchLimited(limit, projection, _mlyCache.images.rtree);
38802           },
38803           signs: function signs(projection) {
38804             var limit = 5;
38805             return searchLimited(limit, projection, _mlyCache.map_features.rtree);
38806           },
38807           mapFeatures: function mapFeatures(projection) {
38808             var limit = 5;
38809             return searchLimited(limit, projection, _mlyCache.points.rtree);
38810           },
38811           cachedImage: function cachedImage(imageKey) {
38812             return _mlyCache.images.forImageKey[imageKey];
38813           },
38814           sequences: function sequences(projection) {
38815             var viewport = projection.clipExtent();
38816             var min = [viewport[0][0], viewport[1][1]];
38817             var max = [viewport[1][0], viewport[0][1]];
38818             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
38819             var sequenceKeys = {}; // all sequences for images in viewport
38820
38821             _mlyCache.images.rtree.search(bbox).forEach(function (d) {
38822               var sequenceKey = _mlyCache.sequences.forImageKey[d.data.key];
38823
38824               if (sequenceKey) {
38825                 sequenceKeys[sequenceKey] = true;
38826               }
38827             }); // Return lineStrings for the sequences
38828
38829
38830             return Object.keys(sequenceKeys).map(function (sequenceKey) {
38831               return _mlyCache.sequences.lineString[sequenceKey];
38832             });
38833           },
38834           signsSupported: function signsSupported() {
38835             return true;
38836           },
38837           loadImages: function loadImages(projection) {
38838             loadTiles('images', apibase + 'images?sort_by=key&', projection);
38839             loadTiles('sequences', apibase + 'sequences?sort_by=key&', projection);
38840           },
38841           loadSigns: function loadSigns(projection) {
38842             loadTiles('map_features', apibase + 'map_features?layers=trafficsigns&min_nbr_image_detections=2&sort_by=key&', projection);
38843           },
38844           loadMapFeatures: function loadMapFeatures(projection) {
38845             loadTiles('points', apibase + 'map_features?layers=points&min_nbr_image_detections=2&sort_by=key&values=' + mapFeatureConfig.values + '&', projection);
38846           },
38847           ensureViewerLoaded: function ensureViewerLoaded(context) {
38848             if (_loadViewerPromise) return _loadViewerPromise; // add mly-wrapper
38849
38850             var wrap = context.container().select('.photoviewer').selectAll('.mly-wrapper').data([0]);
38851             wrap.enter().append('div').attr('id', 'ideditor-mly').attr('class', 'photo-wrapper mly-wrapper').classed('hide', true);
38852             var that = this;
38853             _loadViewerPromise = new Promise(function (resolve, reject) {
38854               var loadedCount = 0;
38855
38856               function loaded() {
38857                 loadedCount += 1; // wait until both files are loaded
38858
38859                 if (loadedCount === 2) resolve();
38860               }
38861
38862               var head = select('head'); // load mapillary-viewercss
38863
38864               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 () {
38865                 reject();
38866               }); // load mapillary-viewerjs
38867
38868               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 () {
38869                 reject();
38870               });
38871             })["catch"](function () {
38872               _loadViewerPromise = null;
38873             }).then(function () {
38874               that.initViewer(context);
38875             });
38876             return _loadViewerPromise;
38877           },
38878           loadSignResources: function loadSignResources(context) {
38879             context.ui().svgDefs.addSprites(['mapillary-sprite'], false
38880             /* don't override colors */
38881             );
38882             return this;
38883           },
38884           loadObjectResources: function loadObjectResources(context) {
38885             context.ui().svgDefs.addSprites(['mapillary-object-sprite'], false
38886             /* don't override colors */
38887             );
38888             return this;
38889           },
38890           resetTags: function resetTags() {
38891             if (_mlyViewer && !_mlyFallback) {
38892               _mlyViewer.getComponent('tag').removeAll(); // remove previous detections
38893
38894             }
38895           },
38896           showFeatureDetections: function showFeatureDetections(value) {
38897             _mlyShowFeatureDetections = value;
38898
38899             if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
38900               this.resetTags();
38901             }
38902           },
38903           showSignDetections: function showSignDetections(value) {
38904             _mlyShowSignDetections = value;
38905
38906             if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
38907               this.resetTags();
38908             }
38909           },
38910           filterViewer: function filterViewer(context) {
38911             var showsPano = context.photos().showsPanoramic();
38912             var showsFlat = context.photos().showsFlat();
38913             var fromDate = context.photos().fromDate();
38914             var toDate = context.photos().toDate();
38915             var usernames = context.photos().usernames();
38916             var filter = ['all'];
38917             if (!showsPano) filter.push(['==', 'pano', false]);
38918             if (!showsFlat && showsPano) filter.push(['==', 'pano', true]);
38919             if (usernames && usernames.length) filter.push(['==', 'username', usernames[0]]);
38920
38921             if (fromDate) {
38922               var fromTimestamp = new Date(fromDate).getTime();
38923               filter.push(['>=', 'capturedAt', fromTimestamp]);
38924             }
38925
38926             if (toDate) {
38927               var toTimestamp = new Date(toDate).getTime();
38928               filter.push(['>=', 'capturedAt', toTimestamp]);
38929             }
38930
38931             if (_mlyViewer) {
38932               _mlyViewer.setFilter(filter);
38933             }
38934
38935             _mlyViewerFilter = filter;
38936             return filter;
38937           },
38938           showViewer: function showViewer(context) {
38939             var wrap = context.container().select('.photoviewer').classed('hide', false);
38940             var isHidden = wrap.selectAll('.photo-wrapper.mly-wrapper.hide').size();
38941
38942             if (isHidden && _mlyViewer) {
38943               wrap.selectAll('.photo-wrapper:not(.mly-wrapper)').classed('hide', true);
38944               wrap.selectAll('.photo-wrapper.mly-wrapper').classed('hide', false);
38945
38946               _mlyViewer.resize();
38947             }
38948
38949             return this;
38950           },
38951           hideViewer: function hideViewer(context) {
38952             _mlyActiveImage = null;
38953             _mlySelectedImageKey = null;
38954
38955             if (!_mlyFallback && _mlyViewer) {
38956               _mlyViewer.getComponent('sequence').stop();
38957             }
38958
38959             var viewer = context.container().select('.photoviewer');
38960             if (!viewer.empty()) viewer.datum(null);
38961             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
38962             this.updateUrlImage(null);
38963             dispatch$4.call('nodeChanged');
38964             return this.setStyles(context, null, true);
38965           },
38966           parsePagination: parsePagination,
38967           updateUrlImage: function updateUrlImage(imageKey) {
38968             if (!window.mocha) {
38969               var hash = utilStringQs(window.location.hash);
38970
38971               if (imageKey) {
38972                 hash.photo = 'mapillary/' + imageKey;
38973               } else {
38974                 delete hash.photo;
38975               }
38976
38977               window.location.replace('#' + utilQsString(hash, true));
38978             }
38979           },
38980           highlightDetection: function highlightDetection(detection) {
38981             if (detection) {
38982               _mlyHighlightedDetection = detection.detection_key;
38983             }
38984
38985             return this;
38986           },
38987           initViewer: function initViewer(context) {
38988             var that = this;
38989             if (!window.Mapillary) return;
38990             var opts = {
38991               baseImageSize: 320,
38992               component: {
38993                 cover: false,
38994                 keyboard: false,
38995                 tag: true
38996               }
38997             }; // Disable components requiring WebGL support
38998
38999             if (!Mapillary.isSupported() && Mapillary.isFallbackSupported()) {
39000               _mlyFallback = true;
39001               opts.component = {
39002                 cover: false,
39003                 direction: false,
39004                 imagePlane: false,
39005                 keyboard: false,
39006                 mouse: false,
39007                 sequence: false,
39008                 tag: false,
39009                 image: true,
39010                 // fallback
39011                 navigation: true // fallback
39012
39013               };
39014             }
39015
39016             _mlyViewer = new Mapillary.Viewer('ideditor-mly', clientId, null, opts);
39017
39018             _mlyViewer.on('nodechanged', nodeChanged);
39019
39020             _mlyViewer.on('bearingchanged', bearingChanged);
39021
39022             if (_mlyViewerFilter) {
39023               _mlyViewer.setFilter(_mlyViewerFilter);
39024             } // Register viewer resize handler
39025
39026
39027             context.ui().photoviewer.on('resize.mapillary', function () {
39028               if (_mlyViewer) _mlyViewer.resize();
39029             }); // nodeChanged: called after the viewer has changed images and is ready.
39030             //
39031             // There is some logic here to batch up clicks into a _mlyClicks array
39032             // because the user might click on a lot of markers quickly and nodechanged
39033             // may be called out of order asynchronously.
39034             //
39035             // Clicks are added to the array in `selectedImage` and removed here.
39036             //
39037
39038             function nodeChanged(node) {
39039               that.resetTags();
39040               var clicks = _mlyClicks;
39041               var index = clicks.indexOf(node.key);
39042               var selectedKey = _mlySelectedImageKey;
39043               that.setActiveImage(node);
39044
39045               if (index > -1) {
39046                 // `nodechanged` initiated from clicking on a marker..
39047                 clicks.splice(index, 1); // remove the click
39048                 // If `node.key` matches the current _mlySelectedImageKey, call `selectImage()`
39049                 // one more time to update the detections and attribution..
39050
39051                 if (node.key === selectedKey) {
39052                   that.selectImage(context, _mlySelectedImageKey, true);
39053                 }
39054               } else {
39055                 // `nodechanged` initiated from the Mapillary viewer controls..
39056                 var loc = node.computedLatLon ? [node.computedLatLon.lon, node.computedLatLon.lat] : [node.latLon.lon, node.latLon.lat];
39057                 context.map().centerEase(loc);
39058                 that.selectImage(context, node.key, true);
39059               }
39060
39061               dispatch$4.call('nodeChanged');
39062             }
39063
39064             function bearingChanged(e) {
39065               dispatch$4.call('bearingChanged', undefined, e);
39066             }
39067           },
39068           // Pass in the image key string as `imageKey`.
39069           // This allows images to be selected from places that dont have access
39070           // to the full image datum (like the street signs layer or the js viewer)
39071           selectImage: function selectImage(context, imageKey, fromViewer) {
39072             _mlySelectedImageKey = imageKey;
39073             this.updateUrlImage(imageKey);
39074             var d = _mlyCache.images.forImageKey[imageKey];
39075             var viewer = context.container().select('.photoviewer');
39076             if (!viewer.empty()) viewer.datum(d);
39077             imageKey = d && d.key || imageKey;
39078
39079             if (!fromViewer && imageKey) {
39080               _mlyClicks.push(imageKey);
39081             }
39082
39083             this.setStyles(context, null, true);
39084
39085             if (_mlyShowFeatureDetections) {
39086               this.updateDetections(imageKey, apibase + 'image_detections?layers=points&values=' + mapFeatureConfig.values + '&image_keys=' + imageKey);
39087             }
39088
39089             if (_mlyShowSignDetections) {
39090               this.updateDetections(imageKey, apibase + 'image_detections?layers=trafficsigns&image_keys=' + imageKey);
39091             }
39092
39093             if (_mlyViewer && imageKey) {
39094               _mlyViewer.moveToKey(imageKey)["catch"](function (e) {
39095                 console.error('mly3', e);
39096               }); // eslint-disable-line no-console
39097
39098             }
39099
39100             return this;
39101           },
39102           getActiveImage: function getActiveImage() {
39103             return _mlyActiveImage;
39104           },
39105           getSelectedImageKey: function getSelectedImageKey() {
39106             return _mlySelectedImageKey;
39107           },
39108           getSequenceKeyForImageKey: function getSequenceKeyForImageKey(imageKey) {
39109             return _mlyCache.sequences.forImageKey[imageKey];
39110           },
39111           setActiveImage: function setActiveImage(node) {
39112             if (node) {
39113               _mlyActiveImage = {
39114                 ca: node.originalCA,
39115                 key: node.key,
39116                 loc: [node.originalLatLon.lon, node.originalLatLon.lat],
39117                 pano: node.pano
39118               };
39119             } else {
39120               _mlyActiveImage = null;
39121             }
39122           },
39123           // Updates the currently highlighted sequence and selected bubble.
39124           // Reset is only necessary when interacting with the viewport because
39125           // this implicitly changes the currently selected bubble/sequence
39126           setStyles: function setStyles(context, hovered, reset) {
39127             if (reset) {
39128               // reset all layers
39129               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false);
39130               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
39131             }
39132
39133             var hoveredImageKey = hovered && hovered.key;
39134             var hoveredSequenceKey = hoveredImageKey && this.getSequenceKeyForImageKey(hoveredImageKey);
39135             var hoveredLineString = hoveredSequenceKey && _mlyCache.sequences.lineString[hoveredSequenceKey];
39136             var hoveredImageKeys = hoveredLineString && hoveredLineString.properties.coordinateProperties.image_keys || [];
39137             var selectedImageKey = _mlySelectedImageKey;
39138             var selectedSequenceKey = selectedImageKey && this.getSequenceKeyForImageKey(selectedImageKey);
39139             var selectedLineString = selectedSequenceKey && _mlyCache.sequences.lineString[selectedSequenceKey];
39140             var selectedImageKeys = selectedLineString && selectedLineString.properties.coordinateProperties.image_keys || []; // highlight sibling viewfields on either the selected or the hovered sequences
39141
39142             var highlightedImageKeys = utilArrayUnion(hoveredImageKeys, selectedImageKeys);
39143             context.container().selectAll('.layer-mapillary .viewfield-group').classed('highlighted', function (d) {
39144               return highlightedImageKeys.indexOf(d.key) !== -1;
39145             }).classed('hovered', function (d) {
39146               return d.key === hoveredImageKey;
39147             });
39148             context.container().selectAll('.layer-mapillary .sequence').classed('highlighted', function (d) {
39149               return d.properties.key === hoveredSequenceKey;
39150             }).classed('currentView', function (d) {
39151               return d.properties.key === selectedSequenceKey;
39152             }); // update viewfields if needed
39153
39154             context.container().selectAll('.viewfield-group .viewfield').attr('d', viewfieldPath);
39155
39156             function viewfieldPath() {
39157               var d = this.parentNode.__data__;
39158
39159               if (d.pano && d.key !== selectedImageKey) {
39160                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
39161               } else {
39162                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
39163               }
39164             }
39165
39166             return this;
39167           },
39168           updateDetections: function updateDetections(imageKey, url) {
39169             if (!_mlyViewer || _mlyFallback) return;
39170             if (!imageKey) return;
39171
39172             if (!_mlyCache.image_detections.forImageKey[imageKey]) {
39173               loadData('image_detections', url).then(function () {
39174                 showDetections(_mlyCache.image_detections.forImageKey[imageKey] || []);
39175               });
39176             } else {
39177               showDetections(_mlyCache.image_detections.forImageKey[imageKey]);
39178             }
39179
39180             function showDetections(detections) {
39181               detections.forEach(function (data) {
39182                 var tag = makeTag(data);
39183
39184                 if (tag) {
39185                   var tagComponent = _mlyViewer.getComponent('tag');
39186
39187                   tagComponent.add([tag]);
39188                 }
39189               });
39190             }
39191
39192             function makeTag(data) {
39193               var valueParts = data.value.split('--');
39194               if (!valueParts.length) return;
39195               var tag;
39196               var text;
39197               var color = 0xffffff;
39198
39199               if (_mlyHighlightedDetection === data.key) {
39200                 color = 0xffff00;
39201                 text = valueParts[1];
39202
39203                 if (text === 'flat' || text === 'discrete' || text === 'sign') {
39204                   text = valueParts[2];
39205                 }
39206
39207                 text = text.replace(/-/g, ' ');
39208                 text = text.charAt(0).toUpperCase() + text.slice(1);
39209                 _mlyHighlightedDetection = null;
39210               }
39211
39212               if (data.shape.type === 'Polygon') {
39213                 var polygonGeometry = new Mapillary.TagComponent.PolygonGeometry(data.shape.coordinates[0]);
39214                 tag = new Mapillary.TagComponent.OutlineTag(data.key, polygonGeometry, {
39215                   text: text,
39216                   textColor: color,
39217                   lineColor: color,
39218                   lineWidth: 2,
39219                   fillColor: color,
39220                   fillOpacity: 0.3
39221                 });
39222               } else if (data.shape.type === 'Point') {
39223                 var pointGeometry = new Mapillary.TagComponent.PointGeometry(data.shape.coordinates[0]);
39224                 tag = new Mapillary.TagComponent.SpotTag(data.key, pointGeometry, {
39225                   text: text,
39226                   color: color,
39227                   textColor: color
39228                 });
39229               }
39230
39231               return tag;
39232             }
39233           },
39234           cache: function cache() {
39235             return _mlyCache;
39236           }
39237         };
39238
39239         function validationIssue(attrs) {
39240           this.type = attrs.type; // required - name of rule that created the issue (e.g. 'missing_tag')
39241
39242           this.subtype = attrs.subtype; // optional - category of the issue within the type (e.g. 'relation_type' under 'missing_tag')
39243
39244           this.severity = attrs.severity; // required - 'warning' or 'error'
39245
39246           this.message = attrs.message; // required - function returning localized string
39247
39248           this.reference = attrs.reference; // optional - function(selection) to render reference information
39249
39250           this.entityIds = attrs.entityIds; // optional - array of IDs of entities involved in the issue
39251
39252           this.loc = attrs.loc; // optional - [lon, lat] to zoom in on to see the issue
39253
39254           this.data = attrs.data; // optional - object containing extra data for the fixes
39255
39256           this.dynamicFixes = attrs.dynamicFixes; // optional - function(context) returning fixes
39257
39258           this.hash = attrs.hash; // optional - string to further differentiate the issue
39259
39260           this.id = generateID.apply(this); // generated - see below
39261
39262           this.autoFix = null; // generated - if autofix exists, will be set below
39263           // A unique, deterministic string hash.
39264           // Issues with identical id values are considered identical.
39265
39266           function generateID() {
39267             var parts = [this.type];
39268
39269             if (this.hash) {
39270               // subclasses can pass in their own differentiator
39271               parts.push(this.hash);
39272             }
39273
39274             if (this.subtype) {
39275               parts.push(this.subtype);
39276             } // include the entities this issue is for
39277             // (sort them so the id is deterministic)
39278
39279
39280             if (this.entityIds) {
39281               var entityKeys = this.entityIds.slice().sort();
39282               parts.push.apply(parts, entityKeys);
39283             }
39284
39285             return parts.join(':');
39286           }
39287
39288           this.extent = function (resolver) {
39289             if (this.loc) {
39290               return geoExtent(this.loc);
39291             }
39292
39293             if (this.entityIds && this.entityIds.length) {
39294               return this.entityIds.reduce(function (extent, entityId) {
39295                 return extent.extend(resolver.entity(entityId).extent(resolver));
39296               }, geoExtent());
39297             }
39298
39299             return null;
39300           };
39301
39302           this.fixes = function (context) {
39303             var fixes = this.dynamicFixes ? this.dynamicFixes(context) : [];
39304             var issue = this;
39305
39306             if (issue.severity === 'warning') {
39307               // allow ignoring any issue that's not an error
39308               fixes.push(new validationIssueFix({
39309                 title: _t.html('issues.fix.ignore_issue.title'),
39310                 icon: 'iD-icon-close',
39311                 onClick: function onClick() {
39312                   context.validator().ignoreIssue(this.issue.id);
39313                 }
39314               }));
39315             }
39316
39317             fixes.forEach(function (fix) {
39318               // the id doesn't matter as long as it's unique to this issue/fix
39319               fix.id = fix.title; // add a reference to the issue for use in actions
39320
39321               fix.issue = issue;
39322
39323               if (fix.autoArgs) {
39324                 issue.autoFix = fix;
39325               }
39326             });
39327             return fixes;
39328           };
39329         }
39330         function validationIssueFix(attrs) {
39331           this.title = attrs.title; // Required
39332
39333           this.onClick = attrs.onClick; // Optional - the function to run to apply the fix
39334
39335           this.disabledReason = attrs.disabledReason; // Optional - a string explaining why the fix is unavailable, if any
39336
39337           this.icon = attrs.icon; // Optional - shows 'iD-icon-wrench' if not set
39338
39339           this.entityIds = attrs.entityIds || []; // Optional - used for hover-higlighting.
39340
39341           this.autoArgs = attrs.autoArgs; // Optional - pass [actions, annotation] arglist if this fix can automatically run
39342
39343           this.issue = null; // Generated link - added by validationIssue
39344         }
39345
39346         var buildRuleChecks = function buildRuleChecks() {
39347           return {
39348             equals: function equals(_equals) {
39349               return function (tags) {
39350                 return Object.keys(_equals).every(function (k) {
39351                   return _equals[k] === tags[k];
39352                 });
39353               };
39354             },
39355             notEquals: function notEquals(_notEquals) {
39356               return function (tags) {
39357                 return Object.keys(_notEquals).some(function (k) {
39358                   return _notEquals[k] !== tags[k];
39359                 });
39360               };
39361             },
39362             absence: function absence(_absence) {
39363               return function (tags) {
39364                 return Object.keys(tags).indexOf(_absence) === -1;
39365               };
39366             },
39367             presence: function presence(_presence) {
39368               return function (tags) {
39369                 return Object.keys(tags).indexOf(_presence) > -1;
39370               };
39371             },
39372             greaterThan: function greaterThan(_greaterThan) {
39373               var key = Object.keys(_greaterThan)[0];
39374               var value = _greaterThan[key];
39375               return function (tags) {
39376                 return tags[key] > value;
39377               };
39378             },
39379             greaterThanEqual: function greaterThanEqual(_greaterThanEqual) {
39380               var key = Object.keys(_greaterThanEqual)[0];
39381               var value = _greaterThanEqual[key];
39382               return function (tags) {
39383                 return tags[key] >= value;
39384               };
39385             },
39386             lessThan: function lessThan(_lessThan) {
39387               var key = Object.keys(_lessThan)[0];
39388               var value = _lessThan[key];
39389               return function (tags) {
39390                 return tags[key] < value;
39391               };
39392             },
39393             lessThanEqual: function lessThanEqual(_lessThanEqual) {
39394               var key = Object.keys(_lessThanEqual)[0];
39395               var value = _lessThanEqual[key];
39396               return function (tags) {
39397                 return tags[key] <= value;
39398               };
39399             },
39400             positiveRegex: function positiveRegex(_positiveRegex) {
39401               var tagKey = Object.keys(_positiveRegex)[0];
39402
39403               var expression = _positiveRegex[tagKey].join('|');
39404
39405               var regex = new RegExp(expression);
39406               return function (tags) {
39407                 return regex.test(tags[tagKey]);
39408               };
39409             },
39410             negativeRegex: function negativeRegex(_negativeRegex) {
39411               var tagKey = Object.keys(_negativeRegex)[0];
39412
39413               var expression = _negativeRegex[tagKey].join('|');
39414
39415               var regex = new RegExp(expression);
39416               return function (tags) {
39417                 return !regex.test(tags[tagKey]);
39418               };
39419             }
39420           };
39421         };
39422
39423         var buildLineKeys = function buildLineKeys() {
39424           return {
39425             highway: {
39426               rest_area: true,
39427               services: true
39428             },
39429             railway: {
39430               roundhouse: true,
39431               station: true,
39432               traverser: true,
39433               turntable: true,
39434               wash: true
39435             }
39436           };
39437         };
39438
39439         var serviceMapRules = {
39440           init: function init() {
39441             this._ruleChecks = buildRuleChecks();
39442             this._validationRules = [];
39443             this._areaKeys = osmAreaKeys;
39444             this._lineKeys = buildLineKeys();
39445           },
39446           // list of rules only relevant to tag checks...
39447           filterRuleChecks: function filterRuleChecks(selector) {
39448             var _ruleChecks = this._ruleChecks;
39449             return Object.keys(selector).reduce(function (rules, key) {
39450               if (['geometry', 'error', 'warning'].indexOf(key) === -1) {
39451                 rules.push(_ruleChecks[key](selector[key]));
39452               }
39453
39454               return rules;
39455             }, []);
39456           },
39457           // builds tagMap from mapcss-parse selector object...
39458           buildTagMap: function buildTagMap(selector) {
39459             var getRegexValues = function getRegexValues(regexes) {
39460               return regexes.map(function (regex) {
39461                 return regex.replace(/\$|\^/g, '');
39462               });
39463             };
39464
39465             var tagMap = Object.keys(selector).reduce(function (expectedTags, key) {
39466               var values;
39467               var isRegex = /regex/gi.test(key);
39468               var isEqual = /equals/gi.test(key);
39469
39470               if (isRegex || isEqual) {
39471                 Object.keys(selector[key]).forEach(function (selectorKey) {
39472                   values = isEqual ? [selector[key][selectorKey]] : getRegexValues(selector[key][selectorKey]);
39473
39474                   if (expectedTags.hasOwnProperty(selectorKey)) {
39475                     values = values.concat(expectedTags[selectorKey]);
39476                   }
39477
39478                   expectedTags[selectorKey] = values;
39479                 });
39480               } else if (/(greater|less)Than(Equal)?|presence/g.test(key)) {
39481                 var tagKey = /presence/.test(key) ? selector[key] : Object.keys(selector[key])[0];
39482                 values = [selector[key][tagKey]];
39483
39484                 if (expectedTags.hasOwnProperty(tagKey)) {
39485                   values = values.concat(expectedTags[tagKey]);
39486                 }
39487
39488                 expectedTags[tagKey] = values;
39489               }
39490
39491               return expectedTags;
39492             }, {});
39493             return tagMap;
39494           },
39495           // inspired by osmWay#isArea()
39496           inferGeometry: function inferGeometry(tagMap) {
39497             var _lineKeys = this._lineKeys;
39498             var _areaKeys = this._areaKeys;
39499
39500             var keyValueDoesNotImplyArea = function keyValueDoesNotImplyArea(key) {
39501               return utilArrayIntersection(tagMap[key], Object.keys(_areaKeys[key])).length > 0;
39502             };
39503
39504             var keyValueImpliesLine = function keyValueImpliesLine(key) {
39505               return utilArrayIntersection(tagMap[key], Object.keys(_lineKeys[key])).length > 0;
39506             };
39507
39508             if (tagMap.hasOwnProperty('area')) {
39509               if (tagMap.area.indexOf('yes') > -1) {
39510                 return 'area';
39511               }
39512
39513               if (tagMap.area.indexOf('no') > -1) {
39514                 return 'line';
39515               }
39516             }
39517
39518             for (var key in tagMap) {
39519               if (key in _areaKeys && !keyValueDoesNotImplyArea(key)) {
39520                 return 'area';
39521               }
39522
39523               if (key in _lineKeys && keyValueImpliesLine(key)) {
39524                 return 'area';
39525               }
39526             }
39527
39528             return 'line';
39529           },
39530           // adds from mapcss-parse selector check...
39531           addRule: function addRule(selector) {
39532             var rule = {
39533               // checks relevant to mapcss-selector
39534               checks: this.filterRuleChecks(selector),
39535               // true if all conditions for a tag error are true..
39536               matches: function matches(entity) {
39537                 return this.checks.every(function (check) {
39538                   return check(entity.tags);
39539                 });
39540               },
39541               // borrowed from Way#isArea()
39542               inferredGeometry: this.inferGeometry(this.buildTagMap(selector), this._areaKeys),
39543               geometryMatches: function geometryMatches(entity, graph) {
39544                 if (entity.type === 'node' || entity.type === 'relation') {
39545                   return selector.geometry === entity.type;
39546                 } else if (entity.type === 'way') {
39547                   return this.inferredGeometry === entity.geometry(graph);
39548                 }
39549               },
39550               // when geometries match and tag matches are present, return a warning...
39551               findIssues: function findIssues(entity, graph, issues) {
39552                 if (this.geometryMatches(entity, graph) && this.matches(entity)) {
39553                   var severity = Object.keys(selector).indexOf('error') > -1 ? 'error' : 'warning';
39554                   var _message = selector[severity];
39555                   issues.push(new validationIssue({
39556                     type: 'maprules',
39557                     severity: severity,
39558                     message: function message() {
39559                       return _message;
39560                     },
39561                     entityIds: [entity.id]
39562                   }));
39563                 }
39564               }
39565             };
39566
39567             this._validationRules.push(rule);
39568           },
39569           clearRules: function clearRules() {
39570             this._validationRules = [];
39571           },
39572           // returns validationRules...
39573           validationRules: function validationRules() {
39574             return this._validationRules;
39575           },
39576           // returns ruleChecks
39577           ruleChecks: function ruleChecks() {
39578             return this._ruleChecks;
39579           }
39580         };
39581
39582         var apibase$1 = 'https://nominatim.openstreetmap.org/';
39583         var _inflight = {};
39584
39585         var _nominatimCache;
39586
39587         var serviceNominatim = {
39588           init: function init() {
39589             _inflight = {};
39590             _nominatimCache = new RBush();
39591           },
39592           reset: function reset() {
39593             Object.values(_inflight).forEach(function (controller) {
39594               controller.abort();
39595             });
39596             _inflight = {};
39597             _nominatimCache = new RBush();
39598           },
39599           countryCode: function countryCode(location, callback) {
39600             this.reverse(location, function (err, result) {
39601               if (err) {
39602                 return callback(err);
39603               } else if (result.address) {
39604                 return callback(null, result.address.country_code);
39605               } else {
39606                 return callback('Unable to geocode', null);
39607               }
39608             });
39609           },
39610           reverse: function reverse(loc, callback) {
39611             var cached = _nominatimCache.search({
39612               minX: loc[0],
39613               minY: loc[1],
39614               maxX: loc[0],
39615               maxY: loc[1]
39616             });
39617
39618             if (cached.length > 0) {
39619               if (callback) callback(null, cached[0].data);
39620               return;
39621             }
39622
39623             var params = {
39624               zoom: 13,
39625               format: 'json',
39626               addressdetails: 1,
39627               lat: loc[1],
39628               lon: loc[0]
39629             };
39630             var url = apibase$1 + 'reverse?' + utilQsString(params);
39631             if (_inflight[url]) return;
39632             var controller = new AbortController();
39633             _inflight[url] = controller;
39634             d3_json(url, {
39635               signal: controller.signal
39636             }).then(function (result) {
39637               delete _inflight[url];
39638
39639               if (result && result.error) {
39640                 throw new Error(result.error);
39641               }
39642
39643               var extent = geoExtent(loc).padByMeters(200);
39644
39645               _nominatimCache.insert(Object.assign(extent.bbox(), {
39646                 data: result
39647               }));
39648
39649               if (callback) callback(null, result);
39650             })["catch"](function (err) {
39651               delete _inflight[url];
39652               if (err.name === 'AbortError') return;
39653               if (callback) callback(err.message);
39654             });
39655           },
39656           search: function search(val, callback) {
39657             var searchVal = encodeURIComponent(val);
39658             var url = apibase$1 + 'search/' + searchVal + '?limit=10&format=json';
39659             if (_inflight[url]) return;
39660             var controller = new AbortController();
39661             _inflight[url] = controller;
39662             d3_json(url, {
39663               signal: controller.signal
39664             }).then(function (result) {
39665               delete _inflight[url];
39666
39667               if (result && result.error) {
39668                 throw new Error(result.error);
39669               }
39670
39671               if (callback) callback(null, result);
39672             })["catch"](function (err) {
39673               delete _inflight[url];
39674               if (err.name === 'AbortError') return;
39675               if (callback) callback(err.message);
39676             });
39677           }
39678         };
39679
39680         var apibase$2 = 'https://openstreetcam.org';
39681         var maxResults$1 = 1000;
39682         var tileZoom$1 = 14;
39683         var tiler$4 = utilTiler().zoomExtent([tileZoom$1, tileZoom$1]).skipNullIsland(true);
39684         var dispatch$5 = dispatch('loadedImages');
39685         var imgZoom = d3_zoom().extent([[0, 0], [320, 240]]).translateExtent([[0, 0], [320, 240]]).scaleExtent([1, 15]);
39686
39687         var _oscCache;
39688
39689         var _oscSelectedImage;
39690
39691         var _loadViewerPromise$1;
39692
39693         function abortRequest$4(controller) {
39694           controller.abort();
39695         }
39696
39697         function maxPageAtZoom$1(z) {
39698           if (z < 15) return 2;
39699           if (z === 15) return 5;
39700           if (z === 16) return 10;
39701           if (z === 17) return 20;
39702           if (z === 18) return 40;
39703           if (z > 18) return 80;
39704         }
39705
39706         function loadTiles$1(which, url, projection) {
39707           var currZoom = Math.floor(geoScaleToZoom(projection.scale()));
39708           var tiles = tiler$4.getTiles(projection); // abort inflight requests that are no longer needed
39709
39710           var cache = _oscCache[which];
39711           Object.keys(cache.inflight).forEach(function (k) {
39712             var wanted = tiles.find(function (tile) {
39713               return k.indexOf(tile.id + ',') === 0;
39714             });
39715
39716             if (!wanted) {
39717               abortRequest$4(cache.inflight[k]);
39718               delete cache.inflight[k];
39719             }
39720           });
39721           tiles.forEach(function (tile) {
39722             loadNextTilePage$1(which, currZoom, url, tile);
39723           });
39724         }
39725
39726         function loadNextTilePage$1(which, currZoom, url, tile) {
39727           var cache = _oscCache[which];
39728           var bbox = tile.extent.bbox();
39729           var maxPages = maxPageAtZoom$1(currZoom);
39730           var nextPage = cache.nextPage[tile.id] || 1;
39731           var params = utilQsString({
39732             ipp: maxResults$1,
39733             page: nextPage,
39734             // client_id: clientId,
39735             bbTopLeft: [bbox.maxY, bbox.minX].join(','),
39736             bbBottomRight: [bbox.minY, bbox.maxX].join(',')
39737           }, true);
39738           if (nextPage > maxPages) return;
39739           var id = tile.id + ',' + String(nextPage);
39740           if (cache.loaded[id] || cache.inflight[id]) return;
39741           var controller = new AbortController();
39742           cache.inflight[id] = controller;
39743           var options = {
39744             method: 'POST',
39745             signal: controller.signal,
39746             body: params,
39747             headers: {
39748               'Content-Type': 'application/x-www-form-urlencoded'
39749             }
39750           };
39751           d3_json(url, options).then(function (data) {
39752             cache.loaded[id] = true;
39753             delete cache.inflight[id];
39754
39755             if (!data || !data.currentPageItems || !data.currentPageItems.length) {
39756               throw new Error('No Data');
39757             }
39758
39759             var features = data.currentPageItems.map(function (item) {
39760               var loc = [+item.lng, +item.lat];
39761               var d;
39762
39763               if (which === 'images') {
39764                 d = {
39765                   loc: loc,
39766                   key: item.id,
39767                   ca: +item.heading,
39768                   captured_at: item.shot_date || item.date_added,
39769                   captured_by: item.username,
39770                   imagePath: item.lth_name,
39771                   sequence_id: item.sequence_id,
39772                   sequence_index: +item.sequence_index
39773                 }; // cache sequence info
39774
39775                 var seq = _oscCache.sequences[d.sequence_id];
39776
39777                 if (!seq) {
39778                   seq = {
39779                     rotation: 0,
39780                     images: []
39781                   };
39782                   _oscCache.sequences[d.sequence_id] = seq;
39783                 }
39784
39785                 seq.images[d.sequence_index] = d;
39786                 _oscCache.images.forImageKey[d.key] = d; // cache imageKey -> image
39787               }
39788
39789               return {
39790                 minX: loc[0],
39791                 minY: loc[1],
39792                 maxX: loc[0],
39793                 maxY: loc[1],
39794                 data: d
39795               };
39796             });
39797             cache.rtree.load(features);
39798
39799             if (data.currentPageItems.length === maxResults$1) {
39800               // more pages to load
39801               cache.nextPage[tile.id] = nextPage + 1;
39802               loadNextTilePage$1(which, currZoom, url, tile);
39803             } else {
39804               cache.nextPage[tile.id] = Infinity; // no more pages to load
39805             }
39806
39807             if (which === 'images') {
39808               dispatch$5.call('loadedImages');
39809             }
39810           })["catch"](function () {
39811             cache.loaded[id] = true;
39812             delete cache.inflight[id];
39813           });
39814         } // partition viewport into higher zoom tiles
39815
39816
39817         function partitionViewport$1(projection) {
39818           var z = geoScaleToZoom(projection.scale());
39819           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
39820
39821           var tiler = utilTiler().zoomExtent([z2, z2]);
39822           return tiler.getTiles(projection).map(function (tile) {
39823             return tile.extent;
39824           });
39825         } // no more than `limit` results per partition.
39826
39827
39828         function searchLimited$1(limit, projection, rtree) {
39829           limit = limit || 5;
39830           return partitionViewport$1(projection).reduce(function (result, extent) {
39831             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
39832               return d.data;
39833             });
39834             return found.length ? result.concat(found) : result;
39835           }, []);
39836         }
39837
39838         var serviceOpenstreetcam = {
39839           init: function init() {
39840             if (!_oscCache) {
39841               this.reset();
39842             }
39843
39844             this.event = utilRebind(this, dispatch$5, 'on');
39845           },
39846           reset: function reset() {
39847             if (_oscCache) {
39848               Object.values(_oscCache.images.inflight).forEach(abortRequest$4);
39849             }
39850
39851             _oscCache = {
39852               images: {
39853                 inflight: {},
39854                 loaded: {},
39855                 nextPage: {},
39856                 rtree: new RBush(),
39857                 forImageKey: {}
39858               },
39859               sequences: {}
39860             };
39861             _oscSelectedImage = null;
39862           },
39863           images: function images(projection) {
39864             var limit = 5;
39865             return searchLimited$1(limit, projection, _oscCache.images.rtree);
39866           },
39867           sequences: function sequences(projection) {
39868             var viewport = projection.clipExtent();
39869             var min = [viewport[0][0], viewport[1][1]];
39870             var max = [viewport[1][0], viewport[0][1]];
39871             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
39872             var sequenceKeys = {}; // all sequences for images in viewport
39873
39874             _oscCache.images.rtree.search(bbox).forEach(function (d) {
39875               sequenceKeys[d.data.sequence_id] = true;
39876             }); // make linestrings from those sequences
39877
39878
39879             var lineStrings = [];
39880             Object.keys(sequenceKeys).forEach(function (sequenceKey) {
39881               var seq = _oscCache.sequences[sequenceKey];
39882               var images = seq && seq.images;
39883
39884               if (images) {
39885                 lineStrings.push({
39886                   type: 'LineString',
39887                   coordinates: images.map(function (d) {
39888                     return d.loc;
39889                   }).filter(Boolean),
39890                   properties: {
39891                     captured_at: images[0] ? images[0].captured_at : null,
39892                     captured_by: images[0] ? images[0].captured_by : null,
39893                     key: sequenceKey
39894                   }
39895                 });
39896               }
39897             });
39898             return lineStrings;
39899           },
39900           cachedImage: function cachedImage(imageKey) {
39901             return _oscCache.images.forImageKey[imageKey];
39902           },
39903           loadImages: function loadImages(projection) {
39904             var url = apibase$2 + '/1.0/list/nearby-photos/';
39905             loadTiles$1('images', url, projection);
39906           },
39907           ensureViewerLoaded: function ensureViewerLoaded(context) {
39908             if (_loadViewerPromise$1) return _loadViewerPromise$1; // add osc-wrapper
39909
39910             var wrap = context.container().select('.photoviewer').selectAll('.osc-wrapper').data([0]);
39911             var that = this;
39912             var wrapEnter = wrap.enter().append('div').attr('class', 'photo-wrapper osc-wrapper').classed('hide', true).call(imgZoom.on('zoom', zoomPan)).on('dblclick.zoom', null);
39913             wrapEnter.append('div').attr('class', 'photo-attribution fillD');
39914             var controlsEnter = wrapEnter.append('div').attr('class', 'photo-controls-wrap').append('div').attr('class', 'photo-controls');
39915             controlsEnter.append('button').on('click.back', step(-1)).html('◄');
39916             controlsEnter.append('button').on('click.rotate-ccw', rotate(-90)).html('⤿');
39917             controlsEnter.append('button').on('click.rotate-cw', rotate(90)).html('⤾');
39918             controlsEnter.append('button').on('click.forward', step(1)).html('►');
39919             wrapEnter.append('div').attr('class', 'osc-image-wrap'); // Register viewer resize handler
39920
39921             context.ui().photoviewer.on('resize.openstreetcam', function (dimensions) {
39922               imgZoom = d3_zoom().extent([[0, 0], dimensions]).translateExtent([[0, 0], dimensions]).scaleExtent([1, 15]).on('zoom', zoomPan);
39923             });
39924
39925             function zoomPan(d3_event) {
39926               var t = d3_event.transform;
39927               context.container().select('.photoviewer .osc-image-wrap').call(utilSetTransform, t.x, t.y, t.k);
39928             }
39929
39930             function rotate(deg) {
39931               return function () {
39932                 if (!_oscSelectedImage) return;
39933                 var sequenceKey = _oscSelectedImage.sequence_id;
39934                 var sequence = _oscCache.sequences[sequenceKey];
39935                 if (!sequence) return;
39936                 var r = sequence.rotation || 0;
39937                 r += deg;
39938                 if (r > 180) r -= 360;
39939                 if (r < -180) r += 360;
39940                 sequence.rotation = r;
39941                 var wrap = context.container().select('.photoviewer .osc-wrapper');
39942                 wrap.transition().duration(100).call(imgZoom.transform, identity$2);
39943                 wrap.selectAll('.osc-image').transition().duration(100).style('transform', 'rotate(' + r + 'deg)');
39944               };
39945             }
39946
39947             function step(stepBy) {
39948               return function () {
39949                 if (!_oscSelectedImage) return;
39950                 var sequenceKey = _oscSelectedImage.sequence_id;
39951                 var sequence = _oscCache.sequences[sequenceKey];
39952                 if (!sequence) return;
39953                 var nextIndex = _oscSelectedImage.sequence_index + stepBy;
39954                 var nextImage = sequence.images[nextIndex];
39955                 if (!nextImage) return;
39956                 context.map().centerEase(nextImage.loc);
39957                 that.selectImage(context, nextImage.key);
39958               };
39959             } // don't need any async loading so resolve immediately
39960
39961
39962             _loadViewerPromise$1 = Promise.resolve();
39963             return _loadViewerPromise$1;
39964           },
39965           showViewer: function showViewer(context) {
39966             var viewer = context.container().select('.photoviewer').classed('hide', false);
39967             var isHidden = viewer.selectAll('.photo-wrapper.osc-wrapper.hide').size();
39968
39969             if (isHidden) {
39970               viewer.selectAll('.photo-wrapper:not(.osc-wrapper)').classed('hide', true);
39971               viewer.selectAll('.photo-wrapper.osc-wrapper').classed('hide', false);
39972             }
39973
39974             return this;
39975           },
39976           hideViewer: function hideViewer(context) {
39977             _oscSelectedImage = null;
39978             this.updateUrlImage(null);
39979             var viewer = context.container().select('.photoviewer');
39980             if (!viewer.empty()) viewer.datum(null);
39981             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
39982             context.container().selectAll('.viewfield-group, .sequence, .icon-sign').classed('currentView', false);
39983             return this.setStyles(context, null, true);
39984           },
39985           selectImage: function selectImage(context, imageKey) {
39986             var d = this.cachedImage(imageKey);
39987             _oscSelectedImage = d;
39988             this.updateUrlImage(imageKey);
39989             var viewer = context.container().select('.photoviewer');
39990             if (!viewer.empty()) viewer.datum(d);
39991             this.setStyles(context, null, true);
39992             context.container().selectAll('.icon-sign').classed('currentView', false);
39993             if (!d) return this;
39994             var wrap = context.container().select('.photoviewer .osc-wrapper');
39995             var imageWrap = wrap.selectAll('.osc-image-wrap');
39996             var attribution = wrap.selectAll('.photo-attribution').html('');
39997             wrap.transition().duration(100).call(imgZoom.transform, identity$2);
39998             imageWrap.selectAll('.osc-image').remove();
39999
40000             if (d) {
40001               var sequence = _oscCache.sequences[d.sequence_id];
40002               var r = sequence && sequence.rotation || 0;
40003               imageWrap.append('img').attr('class', 'osc-image').attr('src', apibase$2 + '/' + d.imagePath).style('transform', 'rotate(' + r + 'deg)');
40004
40005               if (d.captured_by) {
40006                 attribution.append('a').attr('class', 'captured_by').attr('target', '_blank').attr('href', 'https://openstreetcam.org/user/' + encodeURIComponent(d.captured_by)).html('@' + d.captured_by);
40007                 attribution.append('span').html('|');
40008               }
40009
40010               if (d.captured_at) {
40011                 attribution.append('span').attr('class', 'captured_at').html(localeDateString(d.captured_at));
40012                 attribution.append('span').html('|');
40013               }
40014
40015               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');
40016             }
40017
40018             return this;
40019
40020             function localeDateString(s) {
40021               if (!s) return null;
40022               var options = {
40023                 day: 'numeric',
40024                 month: 'short',
40025                 year: 'numeric'
40026               };
40027               var d = new Date(s);
40028               if (isNaN(d.getTime())) return null;
40029               return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
40030             }
40031           },
40032           getSelectedImage: function getSelectedImage() {
40033             return _oscSelectedImage;
40034           },
40035           getSequenceKeyForImage: function getSequenceKeyForImage(d) {
40036             return d && d.sequence_id;
40037           },
40038           // Updates the currently highlighted sequence and selected bubble.
40039           // Reset is only necessary when interacting with the viewport because
40040           // this implicitly changes the currently selected bubble/sequence
40041           setStyles: function setStyles(context, hovered, reset) {
40042             if (reset) {
40043               // reset all layers
40044               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false).classed('currentView', false);
40045               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
40046             }
40047
40048             var hoveredImageKey = hovered && hovered.key;
40049             var hoveredSequenceKey = this.getSequenceKeyForImage(hovered);
40050             var hoveredSequence = hoveredSequenceKey && _oscCache.sequences[hoveredSequenceKey];
40051             var hoveredImageKeys = hoveredSequence && hoveredSequence.images.map(function (d) {
40052               return d.key;
40053             }) || [];
40054             var viewer = context.container().select('.photoviewer');
40055             var selected = viewer.empty() ? undefined : viewer.datum();
40056             var selectedImageKey = selected && selected.key;
40057             var selectedSequenceKey = this.getSequenceKeyForImage(selected);
40058             var selectedSequence = selectedSequenceKey && _oscCache.sequences[selectedSequenceKey];
40059             var selectedImageKeys = selectedSequence && selectedSequence.images.map(function (d) {
40060               return d.key;
40061             }) || []; // highlight sibling viewfields on either the selected or the hovered sequences
40062
40063             var highlightedImageKeys = utilArrayUnion(hoveredImageKeys, selectedImageKeys);
40064             context.container().selectAll('.layer-openstreetcam .viewfield-group').classed('highlighted', function (d) {
40065               return highlightedImageKeys.indexOf(d.key) !== -1;
40066             }).classed('hovered', function (d) {
40067               return d.key === hoveredImageKey;
40068             }).classed('currentView', function (d) {
40069               return d.key === selectedImageKey;
40070             });
40071             context.container().selectAll('.layer-openstreetcam .sequence').classed('highlighted', function (d) {
40072               return d.properties.key === hoveredSequenceKey;
40073             }).classed('currentView', function (d) {
40074               return d.properties.key === selectedSequenceKey;
40075             }); // update viewfields if needed
40076
40077             context.container().selectAll('.viewfield-group .viewfield').attr('d', viewfieldPath);
40078
40079             function viewfieldPath() {
40080               var d = this.parentNode.__data__;
40081
40082               if (d.pano && d.key !== selectedImageKey) {
40083                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
40084               } else {
40085                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
40086               }
40087             }
40088
40089             return this;
40090           },
40091           updateUrlImage: function updateUrlImage(imageKey) {
40092             if (!window.mocha) {
40093               var hash = utilStringQs(window.location.hash);
40094
40095               if (imageKey) {
40096                 hash.photo = 'openstreetcam/' + imageKey;
40097               } else {
40098                 delete hash.photo;
40099               }
40100
40101               window.location.replace('#' + utilQsString(hash, true));
40102             }
40103           },
40104           cache: function cache() {
40105             return _oscCache;
40106           }
40107         };
40108
40109         var FORCED$f = fails(function () {
40110           return new Date(NaN).toJSON() !== null
40111             || Date.prototype.toJSON.call({ toISOString: function () { return 1; } }) !== 1;
40112         });
40113
40114         // `Date.prototype.toJSON` method
40115         // https://tc39.github.io/ecma262/#sec-date.prototype.tojson
40116         _export({ target: 'Date', proto: true, forced: FORCED$f }, {
40117           // eslint-disable-next-line no-unused-vars
40118           toJSON: function toJSON(key) {
40119             var O = toObject(this);
40120             var pv = toPrimitive(O);
40121             return typeof pv == 'number' && !isFinite(pv) ? null : O.toISOString();
40122           }
40123         });
40124
40125         // `URL.prototype.toJSON` method
40126         // https://url.spec.whatwg.org/#dom-url-tojson
40127         _export({ target: 'URL', proto: true, enumerable: true }, {
40128           toJSON: function toJSON() {
40129             return URL.prototype.toString.call(this);
40130           }
40131         });
40132
40133         /**
40134          * Checks if `value` is the
40135          * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
40136          * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
40137          *
40138          * @static
40139          * @memberOf _
40140          * @since 0.1.0
40141          * @category Lang
40142          * @param {*} value The value to check.
40143          * @returns {boolean} Returns `true` if `value` is an object, else `false`.
40144          * @example
40145          *
40146          * _.isObject({});
40147          * // => true
40148          *
40149          * _.isObject([1, 2, 3]);
40150          * // => true
40151          *
40152          * _.isObject(_.noop);
40153          * // => true
40154          *
40155          * _.isObject(null);
40156          * // => false
40157          */
40158         function isObject$1(value) {
40159           var type = _typeof(value);
40160
40161           return value != null && (type == 'object' || type == 'function');
40162         }
40163
40164         /** Detect free variable `global` from Node.js. */
40165         var freeGlobal = (typeof global === "undefined" ? "undefined" : _typeof(global)) == 'object' && global && global.Object === Object && global;
40166
40167         /** Detect free variable `self`. */
40168
40169         var freeSelf = (typeof self === "undefined" ? "undefined" : _typeof(self)) == 'object' && self && self.Object === Object && self;
40170         /** Used as a reference to the global object. */
40171
40172         var root$1 = freeGlobal || freeSelf || Function('return this')();
40173
40174         /**
40175          * Gets the timestamp of the number of milliseconds that have elapsed since
40176          * the Unix epoch (1 January 1970 00:00:00 UTC).
40177          *
40178          * @static
40179          * @memberOf _
40180          * @since 2.4.0
40181          * @category Date
40182          * @returns {number} Returns the timestamp.
40183          * @example
40184          *
40185          * _.defer(function(stamp) {
40186          *   console.log(_.now() - stamp);
40187          * }, _.now());
40188          * // => Logs the number of milliseconds it took for the deferred invocation.
40189          */
40190
40191         var now$1 = function now() {
40192           return root$1.Date.now();
40193         };
40194
40195         /** Built-in value references. */
40196
40197         var _Symbol = root$1.Symbol;
40198
40199         /** Used for built-in method references. */
40200
40201         var objectProto = Object.prototype;
40202         /** Used to check objects for own properties. */
40203
40204         var hasOwnProperty$1 = objectProto.hasOwnProperty;
40205         /**
40206          * Used to resolve the
40207          * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
40208          * of values.
40209          */
40210
40211         var nativeObjectToString = objectProto.toString;
40212         /** Built-in value references. */
40213
40214         var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined;
40215         /**
40216          * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
40217          *
40218          * @private
40219          * @param {*} value The value to query.
40220          * @returns {string} Returns the raw `toStringTag`.
40221          */
40222
40223         function getRawTag(value) {
40224           var isOwn = hasOwnProperty$1.call(value, symToStringTag),
40225               tag = value[symToStringTag];
40226
40227           try {
40228             value[symToStringTag] = undefined;
40229             var unmasked = true;
40230           } catch (e) {}
40231
40232           var result = nativeObjectToString.call(value);
40233
40234           if (unmasked) {
40235             if (isOwn) {
40236               value[symToStringTag] = tag;
40237             } else {
40238               delete value[symToStringTag];
40239             }
40240           }
40241
40242           return result;
40243         }
40244
40245         /** Used for built-in method references. */
40246         var objectProto$1 = Object.prototype;
40247         /**
40248          * Used to resolve the
40249          * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
40250          * of values.
40251          */
40252
40253         var nativeObjectToString$1 = objectProto$1.toString;
40254         /**
40255          * Converts `value` to a string using `Object.prototype.toString`.
40256          *
40257          * @private
40258          * @param {*} value The value to convert.
40259          * @returns {string} Returns the converted string.
40260          */
40261
40262         function objectToString$1(value) {
40263           return nativeObjectToString$1.call(value);
40264         }
40265
40266         /** `Object#toString` result references. */
40267
40268         var nullTag = '[object Null]',
40269             undefinedTag = '[object Undefined]';
40270         /** Built-in value references. */
40271
40272         var symToStringTag$1 = _Symbol ? _Symbol.toStringTag : undefined;
40273         /**
40274          * The base implementation of `getTag` without fallbacks for buggy environments.
40275          *
40276          * @private
40277          * @param {*} value The value to query.
40278          * @returns {string} Returns the `toStringTag`.
40279          */
40280
40281         function baseGetTag(value) {
40282           if (value == null) {
40283             return value === undefined ? undefinedTag : nullTag;
40284           }
40285
40286           return symToStringTag$1 && symToStringTag$1 in Object(value) ? getRawTag(value) : objectToString$1(value);
40287         }
40288
40289         /**
40290          * Checks if `value` is object-like. A value is object-like if it's not `null`
40291          * and has a `typeof` result of "object".
40292          *
40293          * @static
40294          * @memberOf _
40295          * @since 4.0.0
40296          * @category Lang
40297          * @param {*} value The value to check.
40298          * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
40299          * @example
40300          *
40301          * _.isObjectLike({});
40302          * // => true
40303          *
40304          * _.isObjectLike([1, 2, 3]);
40305          * // => true
40306          *
40307          * _.isObjectLike(_.noop);
40308          * // => false
40309          *
40310          * _.isObjectLike(null);
40311          * // => false
40312          */
40313         function isObjectLike(value) {
40314           return value != null && _typeof(value) == 'object';
40315         }
40316
40317         /** `Object#toString` result references. */
40318
40319         var symbolTag = '[object Symbol]';
40320         /**
40321          * Checks if `value` is classified as a `Symbol` primitive or object.
40322          *
40323          * @static
40324          * @memberOf _
40325          * @since 4.0.0
40326          * @category Lang
40327          * @param {*} value The value to check.
40328          * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
40329          * @example
40330          *
40331          * _.isSymbol(Symbol.iterator);
40332          * // => true
40333          *
40334          * _.isSymbol('abc');
40335          * // => false
40336          */
40337
40338         function isSymbol$1(value) {
40339           return _typeof(value) == 'symbol' || isObjectLike(value) && baseGetTag(value) == symbolTag;
40340         }
40341
40342         /** Used as references for various `Number` constants. */
40343
40344         var NAN = 0 / 0;
40345         /** Used to match leading and trailing whitespace. */
40346
40347         var reTrim = /^\s+|\s+$/g;
40348         /** Used to detect bad signed hexadecimal string values. */
40349
40350         var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
40351         /** Used to detect binary string values. */
40352
40353         var reIsBinary = /^0b[01]+$/i;
40354         /** Used to detect octal string values. */
40355
40356         var reIsOctal = /^0o[0-7]+$/i;
40357         /** Built-in method references without a dependency on `root`. */
40358
40359         var freeParseInt = parseInt;
40360         /**
40361          * Converts `value` to a number.
40362          *
40363          * @static
40364          * @memberOf _
40365          * @since 4.0.0
40366          * @category Lang
40367          * @param {*} value The value to process.
40368          * @returns {number} Returns the number.
40369          * @example
40370          *
40371          * _.toNumber(3.2);
40372          * // => 3.2
40373          *
40374          * _.toNumber(Number.MIN_VALUE);
40375          * // => 5e-324
40376          *
40377          * _.toNumber(Infinity);
40378          * // => Infinity
40379          *
40380          * _.toNumber('3.2');
40381          * // => 3.2
40382          */
40383
40384         function toNumber$1(value) {
40385           if (typeof value == 'number') {
40386             return value;
40387           }
40388
40389           if (isSymbol$1(value)) {
40390             return NAN;
40391           }
40392
40393           if (isObject$1(value)) {
40394             var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
40395             value = isObject$1(other) ? other + '' : other;
40396           }
40397
40398           if (typeof value != 'string') {
40399             return value === 0 ? value : +value;
40400           }
40401
40402           value = value.replace(reTrim, '');
40403           var isBinary = reIsBinary.test(value);
40404           return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value;
40405         }
40406
40407         /** Error message constants. */
40408
40409         var FUNC_ERROR_TEXT = 'Expected a function';
40410         /* Built-in method references for those with the same name as other `lodash` methods. */
40411
40412         var nativeMax = Math.max,
40413             nativeMin = Math.min;
40414         /**
40415          * Creates a debounced function that delays invoking `func` until after `wait`
40416          * milliseconds have elapsed since the last time the debounced function was
40417          * invoked. The debounced function comes with a `cancel` method to cancel
40418          * delayed `func` invocations and a `flush` method to immediately invoke them.
40419          * Provide `options` to indicate whether `func` should be invoked on the
40420          * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
40421          * with the last arguments provided to the debounced function. Subsequent
40422          * calls to the debounced function return the result of the last `func`
40423          * invocation.
40424          *
40425          * **Note:** If `leading` and `trailing` options are `true`, `func` is
40426          * invoked on the trailing edge of the timeout only if the debounced function
40427          * is invoked more than once during the `wait` timeout.
40428          *
40429          * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
40430          * until to the next tick, similar to `setTimeout` with a timeout of `0`.
40431          *
40432          * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
40433          * for details over the differences between `_.debounce` and `_.throttle`.
40434          *
40435          * @static
40436          * @memberOf _
40437          * @since 0.1.0
40438          * @category Function
40439          * @param {Function} func The function to debounce.
40440          * @param {number} [wait=0] The number of milliseconds to delay.
40441          * @param {Object} [options={}] The options object.
40442          * @param {boolean} [options.leading=false]
40443          *  Specify invoking on the leading edge of the timeout.
40444          * @param {number} [options.maxWait]
40445          *  The maximum time `func` is allowed to be delayed before it's invoked.
40446          * @param {boolean} [options.trailing=true]
40447          *  Specify invoking on the trailing edge of the timeout.
40448          * @returns {Function} Returns the new debounced function.
40449          * @example
40450          *
40451          * // Avoid costly calculations while the window size is in flux.
40452          * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
40453          *
40454          * // Invoke `sendMail` when clicked, debouncing subsequent calls.
40455          * jQuery(element).on('click', _.debounce(sendMail, 300, {
40456          *   'leading': true,
40457          *   'trailing': false
40458          * }));
40459          *
40460          * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
40461          * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
40462          * var source = new EventSource('/stream');
40463          * jQuery(source).on('message', debounced);
40464          *
40465          * // Cancel the trailing debounced invocation.
40466          * jQuery(window).on('popstate', debounced.cancel);
40467          */
40468
40469         function debounce(func, wait, options) {
40470           var lastArgs,
40471               lastThis,
40472               maxWait,
40473               result,
40474               timerId,
40475               lastCallTime,
40476               lastInvokeTime = 0,
40477               leading = false,
40478               maxing = false,
40479               trailing = true;
40480
40481           if (typeof func != 'function') {
40482             throw new TypeError(FUNC_ERROR_TEXT);
40483           }
40484
40485           wait = toNumber$1(wait) || 0;
40486
40487           if (isObject$1(options)) {
40488             leading = !!options.leading;
40489             maxing = 'maxWait' in options;
40490             maxWait = maxing ? nativeMax(toNumber$1(options.maxWait) || 0, wait) : maxWait;
40491             trailing = 'trailing' in options ? !!options.trailing : trailing;
40492           }
40493
40494           function invokeFunc(time) {
40495             var args = lastArgs,
40496                 thisArg = lastThis;
40497             lastArgs = lastThis = undefined;
40498             lastInvokeTime = time;
40499             result = func.apply(thisArg, args);
40500             return result;
40501           }
40502
40503           function leadingEdge(time) {
40504             // Reset any `maxWait` timer.
40505             lastInvokeTime = time; // Start the timer for the trailing edge.
40506
40507             timerId = setTimeout(timerExpired, wait); // Invoke the leading edge.
40508
40509             return leading ? invokeFunc(time) : result;
40510           }
40511
40512           function remainingWait(time) {
40513             var timeSinceLastCall = time - lastCallTime,
40514                 timeSinceLastInvoke = time - lastInvokeTime,
40515                 timeWaiting = wait - timeSinceLastCall;
40516             return maxing ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
40517           }
40518
40519           function shouldInvoke(time) {
40520             var timeSinceLastCall = time - lastCallTime,
40521                 timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the
40522             // trailing edge, the system time has gone backwards and we're treating
40523             // it as the trailing edge, or we've hit the `maxWait` limit.
40524
40525             return lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait;
40526           }
40527
40528           function timerExpired() {
40529             var time = now$1();
40530
40531             if (shouldInvoke(time)) {
40532               return trailingEdge(time);
40533             } // Restart the timer.
40534
40535
40536             timerId = setTimeout(timerExpired, remainingWait(time));
40537           }
40538
40539           function trailingEdge(time) {
40540             timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been
40541             // debounced at least once.
40542
40543             if (trailing && lastArgs) {
40544               return invokeFunc(time);
40545             }
40546
40547             lastArgs = lastThis = undefined;
40548             return result;
40549           }
40550
40551           function cancel() {
40552             if (timerId !== undefined) {
40553               clearTimeout(timerId);
40554             }
40555
40556             lastInvokeTime = 0;
40557             lastArgs = lastCallTime = lastThis = timerId = undefined;
40558           }
40559
40560           function flush() {
40561             return timerId === undefined ? result : trailingEdge(now$1());
40562           }
40563
40564           function debounced() {
40565             var time = now$1(),
40566                 isInvoking = shouldInvoke(time);
40567             lastArgs = arguments;
40568             lastThis = this;
40569             lastCallTime = time;
40570
40571             if (isInvoking) {
40572               if (timerId === undefined) {
40573                 return leadingEdge(lastCallTime);
40574               }
40575
40576               if (maxing) {
40577                 // Handle invocations in a tight loop.
40578                 clearTimeout(timerId);
40579                 timerId = setTimeout(timerExpired, wait);
40580                 return invokeFunc(lastCallTime);
40581               }
40582             }
40583
40584             if (timerId === undefined) {
40585               timerId = setTimeout(timerExpired, wait);
40586             }
40587
40588             return result;
40589           }
40590
40591           debounced.cancel = cancel;
40592           debounced.flush = flush;
40593           return debounced;
40594         }
40595
40596         /** Error message constants. */
40597
40598         var FUNC_ERROR_TEXT$1 = 'Expected a function';
40599         /**
40600          * Creates a throttled function that only invokes `func` at most once per
40601          * every `wait` milliseconds. The throttled function comes with a `cancel`
40602          * method to cancel delayed `func` invocations and a `flush` method to
40603          * immediately invoke them. Provide `options` to indicate whether `func`
40604          * should be invoked on the leading and/or trailing edge of the `wait`
40605          * timeout. The `func` is invoked with the last arguments provided to the
40606          * throttled function. Subsequent calls to the throttled function return the
40607          * result of the last `func` invocation.
40608          *
40609          * **Note:** If `leading` and `trailing` options are `true`, `func` is
40610          * invoked on the trailing edge of the timeout only if the throttled function
40611          * is invoked more than once during the `wait` timeout.
40612          *
40613          * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
40614          * until to the next tick, similar to `setTimeout` with a timeout of `0`.
40615          *
40616          * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
40617          * for details over the differences between `_.throttle` and `_.debounce`.
40618          *
40619          * @static
40620          * @memberOf _
40621          * @since 0.1.0
40622          * @category Function
40623          * @param {Function} func The function to throttle.
40624          * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
40625          * @param {Object} [options={}] The options object.
40626          * @param {boolean} [options.leading=true]
40627          *  Specify invoking on the leading edge of the timeout.
40628          * @param {boolean} [options.trailing=true]
40629          *  Specify invoking on the trailing edge of the timeout.
40630          * @returns {Function} Returns the new throttled function.
40631          * @example
40632          *
40633          * // Avoid excessively updating the position while scrolling.
40634          * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
40635          *
40636          * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
40637          * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
40638          * jQuery(element).on('click', throttled);
40639          *
40640          * // Cancel the trailing throttled invocation.
40641          * jQuery(window).on('popstate', throttled.cancel);
40642          */
40643
40644         function throttle(func, wait, options) {
40645           var leading = true,
40646               trailing = true;
40647
40648           if (typeof func != 'function') {
40649             throw new TypeError(FUNC_ERROR_TEXT$1);
40650           }
40651
40652           if (isObject$1(options)) {
40653             leading = 'leading' in options ? !!options.leading : leading;
40654             trailing = 'trailing' in options ? !!options.trailing : trailing;
40655           }
40656
40657           return debounce(func, wait, {
40658             'leading': leading,
40659             'maxWait': wait,
40660             'trailing': trailing
40661           });
40662         }
40663
40664         var hashes = createCommonjsModule(function (module, exports) {
40665           /**
40666            * jshashes - https://github.com/h2non/jshashes
40667            * Released under the "New BSD" license
40668            *
40669            * Algorithms specification:
40670            *
40671            * MD5 - http://www.ietf.org/rfc/rfc1321.txt
40672            * RIPEMD-160 - http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
40673            * SHA1   - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
40674            * SHA256 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
40675            * SHA512 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
40676            * HMAC - http://www.ietf.org/rfc/rfc2104.txt
40677            */
40678           (function () {
40679             var Hashes;
40680
40681             function utf8Encode(str) {
40682               var x,
40683                   y,
40684                   output = '',
40685                   i = -1,
40686                   l;
40687
40688               if (str && str.length) {
40689                 l = str.length;
40690
40691                 while ((i += 1) < l) {
40692                   /* Decode utf-16 surrogate pairs */
40693                   x = str.charCodeAt(i);
40694                   y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
40695
40696                   if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
40697                     x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
40698                     i += 1;
40699                   }
40700                   /* Encode output as utf-8 */
40701
40702
40703                   if (x <= 0x7F) {
40704                     output += String.fromCharCode(x);
40705                   } else if (x <= 0x7FF) {
40706                     output += String.fromCharCode(0xC0 | x >>> 6 & 0x1F, 0x80 | x & 0x3F);
40707                   } else if (x <= 0xFFFF) {
40708                     output += String.fromCharCode(0xE0 | x >>> 12 & 0x0F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F);
40709                   } else if (x <= 0x1FFFFF) {
40710                     output += String.fromCharCode(0xF0 | x >>> 18 & 0x07, 0x80 | x >>> 12 & 0x3F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F);
40711                   }
40712                 }
40713               }
40714
40715               return output;
40716             }
40717
40718             function utf8Decode(str) {
40719               var i,
40720                   ac,
40721                   c1,
40722                   c2,
40723                   c3,
40724                   arr = [],
40725                   l;
40726               i = ac = c1 = c2 = c3 = 0;
40727
40728               if (str && str.length) {
40729                 l = str.length;
40730                 str += '';
40731
40732                 while (i < l) {
40733                   c1 = str.charCodeAt(i);
40734                   ac += 1;
40735
40736                   if (c1 < 128) {
40737                     arr[ac] = String.fromCharCode(c1);
40738                     i += 1;
40739                   } else if (c1 > 191 && c1 < 224) {
40740                     c2 = str.charCodeAt(i + 1);
40741                     arr[ac] = String.fromCharCode((c1 & 31) << 6 | c2 & 63);
40742                     i += 2;
40743                   } else {
40744                     c2 = str.charCodeAt(i + 1);
40745                     c3 = str.charCodeAt(i + 2);
40746                     arr[ac] = String.fromCharCode((c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
40747                     i += 3;
40748                   }
40749                 }
40750               }
40751
40752               return arr.join('');
40753             }
40754             /**
40755              * Add integers, wrapping at 2^32. This uses 16-bit operations internally
40756              * to work around bugs in some JS interpreters.
40757              */
40758
40759
40760             function safe_add(x, y) {
40761               var lsw = (x & 0xFFFF) + (y & 0xFFFF),
40762                   msw = (x >> 16) + (y >> 16) + (lsw >> 16);
40763               return msw << 16 | lsw & 0xFFFF;
40764             }
40765             /**
40766              * Bitwise rotate a 32-bit number to the left.
40767              */
40768
40769
40770             function bit_rol(num, cnt) {
40771               return num << cnt | num >>> 32 - cnt;
40772             }
40773             /**
40774              * Convert a raw string to a hex string
40775              */
40776
40777
40778             function rstr2hex(input, hexcase) {
40779               var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
40780                   output = '',
40781                   x,
40782                   i = 0,
40783                   l = input.length;
40784
40785               for (; i < l; i += 1) {
40786                 x = input.charCodeAt(i);
40787                 output += hex_tab.charAt(x >>> 4 & 0x0F) + hex_tab.charAt(x & 0x0F);
40788               }
40789
40790               return output;
40791             }
40792             /**
40793              * Convert an array of big-endian words to a string
40794              */
40795
40796
40797             function binb2rstr(input) {
40798               var i,
40799                   l = input.length * 32,
40800                   output = '';
40801
40802               for (i = 0; i < l; i += 8) {
40803                 output += String.fromCharCode(input[i >> 5] >>> 24 - i % 32 & 0xFF);
40804               }
40805
40806               return output;
40807             }
40808             /**
40809              * Convert an array of little-endian words to a string
40810              */
40811
40812
40813             function binl2rstr(input) {
40814               var i,
40815                   l = input.length * 32,
40816                   output = '';
40817
40818               for (i = 0; i < l; i += 8) {
40819                 output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF);
40820               }
40821
40822               return output;
40823             }
40824             /**
40825              * Convert a raw string to an array of little-endian words
40826              * Characters >255 have their high-byte silently ignored.
40827              */
40828
40829
40830             function rstr2binl(input) {
40831               var i,
40832                   l = input.length * 8,
40833                   output = Array(input.length >> 2),
40834                   lo = output.length;
40835
40836               for (i = 0; i < lo; i += 1) {
40837                 output[i] = 0;
40838               }
40839
40840               for (i = 0; i < l; i += 8) {
40841                 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << i % 32;
40842               }
40843
40844               return output;
40845             }
40846             /**
40847              * Convert a raw string to an array of big-endian words
40848              * Characters >255 have their high-byte silently ignored.
40849              */
40850
40851
40852             function rstr2binb(input) {
40853               var i,
40854                   l = input.length * 8,
40855                   output = Array(input.length >> 2),
40856                   lo = output.length;
40857
40858               for (i = 0; i < lo; i += 1) {
40859                 output[i] = 0;
40860               }
40861
40862               for (i = 0; i < l; i += 8) {
40863                 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << 24 - i % 32;
40864               }
40865
40866               return output;
40867             }
40868             /**
40869              * Convert a raw string to an arbitrary string encoding
40870              */
40871
40872
40873             function rstr2any(input, encoding) {
40874               var divisor = encoding.length,
40875                   remainders = Array(),
40876                   i,
40877                   q,
40878                   x,
40879                   ld,
40880                   quotient,
40881                   dividend,
40882                   output,
40883                   full_length;
40884               /* Convert to an array of 16-bit big-endian values, forming the dividend */
40885
40886               dividend = Array(Math.ceil(input.length / 2));
40887               ld = dividend.length;
40888
40889               for (i = 0; i < ld; i += 1) {
40890                 dividend[i] = input.charCodeAt(i * 2) << 8 | input.charCodeAt(i * 2 + 1);
40891               }
40892               /**
40893                * Repeatedly perform a long division. The binary array forms the dividend,
40894                * the length of the encoding is the divisor. Once computed, the quotient
40895                * forms the dividend for the next step. We stop when the dividend is zerHashes.
40896                * All remainders are stored for later use.
40897                */
40898
40899
40900               while (dividend.length > 0) {
40901                 quotient = Array();
40902                 x = 0;
40903
40904                 for (i = 0; i < dividend.length; i += 1) {
40905                   x = (x << 16) + dividend[i];
40906                   q = Math.floor(x / divisor);
40907                   x -= q * divisor;
40908
40909                   if (quotient.length > 0 || q > 0) {
40910                     quotient[quotient.length] = q;
40911                   }
40912                 }
40913
40914                 remainders[remainders.length] = x;
40915                 dividend = quotient;
40916               }
40917               /* Convert the remainders to the output string */
40918
40919
40920               output = '';
40921
40922               for (i = remainders.length - 1; i >= 0; i--) {
40923                 output += encoding.charAt(remainders[i]);
40924               }
40925               /* Append leading zero equivalents */
40926
40927
40928               full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
40929
40930               for (i = output.length; i < full_length; i += 1) {
40931                 output = encoding[0] + output;
40932               }
40933
40934               return output;
40935             }
40936             /**
40937              * Convert a raw string to a base-64 string
40938              */
40939
40940
40941             function rstr2b64(input, b64pad) {
40942               var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
40943                   output = '',
40944                   len = input.length,
40945                   i,
40946                   j,
40947                   triplet;
40948               b64pad = b64pad || '=';
40949
40950               for (i = 0; i < len; i += 3) {
40951                 triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
40952
40953                 for (j = 0; j < 4; j += 1) {
40954                   if (i * 8 + j * 6 > input.length * 8) {
40955                     output += b64pad;
40956                   } else {
40957                     output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F);
40958                   }
40959                 }
40960               }
40961
40962               return output;
40963             }
40964
40965             Hashes = {
40966               /**
40967                * @property {String} version
40968                * @readonly
40969                */
40970               VERSION: '1.0.6',
40971
40972               /**
40973                * @member Hashes
40974                * @class Base64
40975                * @constructor
40976                */
40977               Base64: function Base64() {
40978                 // private properties
40979                 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
40980                     pad = '=',
40981                     // URL encoding support @todo
40982                 utf8 = true; // by default enable UTF-8 support encoding
40983                 // public method for encoding
40984
40985                 this.encode = function (input) {
40986                   var i,
40987                       j,
40988                       triplet,
40989                       output = '',
40990                       len = input.length;
40991                   pad = pad || '=';
40992                   input = utf8 ? utf8Encode(input) : input;
40993
40994                   for (i = 0; i < len; i += 3) {
40995                     triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
40996
40997                     for (j = 0; j < 4; j += 1) {
40998                       if (i * 8 + j * 6 > len * 8) {
40999                         output += pad;
41000                       } else {
41001                         output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F);
41002                       }
41003                     }
41004                   }
41005
41006                   return output;
41007                 }; // public method for decoding
41008
41009
41010                 this.decode = function (input) {
41011                   // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
41012                   var i,
41013                       o1,
41014                       o2,
41015                       o3,
41016                       h1,
41017                       h2,
41018                       h3,
41019                       h4,
41020                       bits,
41021                       ac,
41022                       dec = '',
41023                       arr = [];
41024
41025                   if (!input) {
41026                     return input;
41027                   }
41028
41029                   i = ac = 0;
41030                   input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '='
41031                   //input += '';
41032
41033                   do {
41034                     // unpack four hexets into three octets using index points in b64
41035                     h1 = tab.indexOf(input.charAt(i += 1));
41036                     h2 = tab.indexOf(input.charAt(i += 1));
41037                     h3 = tab.indexOf(input.charAt(i += 1));
41038                     h4 = tab.indexOf(input.charAt(i += 1));
41039                     bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
41040                     o1 = bits >> 16 & 0xff;
41041                     o2 = bits >> 8 & 0xff;
41042                     o3 = bits & 0xff;
41043                     ac += 1;
41044
41045                     if (h3 === 64) {
41046                       arr[ac] = String.fromCharCode(o1);
41047                     } else if (h4 === 64) {
41048                       arr[ac] = String.fromCharCode(o1, o2);
41049                     } else {
41050                       arr[ac] = String.fromCharCode(o1, o2, o3);
41051                     }
41052                   } while (i < input.length);
41053
41054                   dec = arr.join('');
41055                   dec = utf8 ? utf8Decode(dec) : dec;
41056                   return dec;
41057                 }; // set custom pad string
41058
41059
41060                 this.setPad = function (str) {
41061                   pad = str || pad;
41062                   return this;
41063                 }; // set custom tab string characters
41064
41065
41066                 this.setTab = function (str) {
41067                   tab = str || tab;
41068                   return this;
41069                 };
41070
41071                 this.setUTF8 = function (bool) {
41072                   if (typeof bool === 'boolean') {
41073                     utf8 = bool;
41074                   }
41075
41076                   return this;
41077                 };
41078               },
41079
41080               /**
41081                * CRC-32 calculation
41082                * @member Hashes
41083                * @method CRC32
41084                * @static
41085                * @param {String} str Input String
41086                * @return {String}
41087                */
41088               CRC32: function CRC32(str) {
41089                 var crc = 0,
41090                     x = 0,
41091                     y = 0,
41092                     table,
41093                     i,
41094                     iTop;
41095                 str = utf8Encode(str);
41096                 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('');
41097                 crc = crc ^ -1;
41098
41099                 for (i = 0, iTop = str.length; i < iTop; i += 1) {
41100                   y = (crc ^ str.charCodeAt(i)) & 0xFF;
41101                   x = '0x' + table.substr(y * 9, 8);
41102                   crc = crc >>> 8 ^ x;
41103                 } // always return a positive number (that's what >>> 0 does)
41104
41105
41106                 return (crc ^ -1) >>> 0;
41107               },
41108
41109               /**
41110                * @member Hashes
41111                * @class MD5
41112                * @constructor
41113                * @param {Object} [config]
41114                *
41115                * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
41116                * Digest Algorithm, as defined in RFC 1321.
41117                * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
41118                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41119                * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
41120                */
41121               MD5: function MD5(options) {
41122                 /**
41123                  * Private config properties. You may need to tweak these to be compatible with
41124                  * the server-side, but the defaults work in most cases.
41125                  * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
41126                  */
41127                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41128                     // hexadecimal output case format. false - lowercase; true - uppercase
41129                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41130                     // base-64 pad character. Defaults to '=' for strict RFC compliance
41131                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding
41132                 // privileged (public) methods
41133
41134                 this.hex = function (s) {
41135                   return rstr2hex(rstr(s), hexcase);
41136                 };
41137
41138                 this.b64 = function (s) {
41139                   return rstr2b64(rstr(s), b64pad);
41140                 };
41141
41142                 this.any = function (s, e) {
41143                   return rstr2any(rstr(s), e);
41144                 };
41145
41146                 this.raw = function (s) {
41147                   return rstr(s);
41148                 };
41149
41150                 this.hex_hmac = function (k, d) {
41151                   return rstr2hex(rstr_hmac(k, d), hexcase);
41152                 };
41153
41154                 this.b64_hmac = function (k, d) {
41155                   return rstr2b64(rstr_hmac(k, d), b64pad);
41156                 };
41157
41158                 this.any_hmac = function (k, d, e) {
41159                   return rstr2any(rstr_hmac(k, d), e);
41160                 };
41161                 /**
41162                  * Perform a simple self-test to see if the VM is working
41163                  * @return {String} Hexadecimal hash sample
41164                  */
41165
41166
41167                 this.vm_test = function () {
41168                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41169                 };
41170                 /**
41171                  * Enable/disable uppercase hexadecimal returned string
41172                  * @param {Boolean}
41173                  * @return {Object} this
41174                  */
41175
41176
41177                 this.setUpperCase = function (a) {
41178                   if (typeof a === 'boolean') {
41179                     hexcase = a;
41180                   }
41181
41182                   return this;
41183                 };
41184                 /**
41185                  * Defines a base64 pad string
41186                  * @param {String} Pad
41187                  * @return {Object} this
41188                  */
41189
41190
41191                 this.setPad = function (a) {
41192                   b64pad = a || b64pad;
41193                   return this;
41194                 };
41195                 /**
41196                  * Defines a base64 pad string
41197                  * @param {Boolean}
41198                  * @return {Object} [this]
41199                  */
41200
41201
41202                 this.setUTF8 = function (a) {
41203                   if (typeof a === 'boolean') {
41204                     utf8 = a;
41205                   }
41206
41207                   return this;
41208                 }; // private methods
41209
41210                 /**
41211                  * Calculate the MD5 of a raw string
41212                  */
41213
41214
41215                 function rstr(s) {
41216                   s = utf8 ? utf8Encode(s) : s;
41217                   return binl2rstr(binl(rstr2binl(s), s.length * 8));
41218                 }
41219                 /**
41220                  * Calculate the HMAC-MD5, of a key and some data (raw strings)
41221                  */
41222
41223
41224                 function rstr_hmac(key, data) {
41225                   var bkey, ipad, opad, hash, i;
41226                   key = utf8 ? utf8Encode(key) : key;
41227                   data = utf8 ? utf8Encode(data) : data;
41228                   bkey = rstr2binl(key);
41229
41230                   if (bkey.length > 16) {
41231                     bkey = binl(bkey, key.length * 8);
41232                   }
41233
41234                   ipad = Array(16), opad = Array(16);
41235
41236                   for (i = 0; i < 16; i += 1) {
41237                     ipad[i] = bkey[i] ^ 0x36363636;
41238                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
41239                   }
41240
41241                   hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
41242                   return binl2rstr(binl(opad.concat(hash), 512 + 128));
41243                 }
41244                 /**
41245                  * Calculate the MD5 of an array of little-endian words, and a bit length.
41246                  */
41247
41248
41249                 function binl(x, len) {
41250                   var i,
41251                       olda,
41252                       oldb,
41253                       oldc,
41254                       oldd,
41255                       a = 1732584193,
41256                       b = -271733879,
41257                       c = -1732584194,
41258                       d = 271733878;
41259                   /* append padding */
41260
41261                   x[len >> 5] |= 0x80 << len % 32;
41262                   x[(len + 64 >>> 9 << 4) + 14] = len;
41263
41264                   for (i = 0; i < x.length; i += 16) {
41265                     olda = a;
41266                     oldb = b;
41267                     oldc = c;
41268                     oldd = d;
41269                     a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
41270                     d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
41271                     c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
41272                     b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
41273                     a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
41274                     d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
41275                     c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
41276                     b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
41277                     a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
41278                     d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
41279                     c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
41280                     b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
41281                     a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
41282                     d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
41283                     c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
41284                     b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
41285                     a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
41286                     d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
41287                     c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
41288                     b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
41289                     a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
41290                     d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
41291                     c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
41292                     b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
41293                     a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
41294                     d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
41295                     c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
41296                     b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
41297                     a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
41298                     d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
41299                     c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
41300                     b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
41301                     a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
41302                     d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
41303                     c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
41304                     b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
41305                     a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
41306                     d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
41307                     c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
41308                     b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
41309                     a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
41310                     d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
41311                     c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
41312                     b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
41313                     a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
41314                     d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
41315                     c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
41316                     b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
41317                     a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
41318                     d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
41319                     c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
41320                     b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
41321                     a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
41322                     d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
41323                     c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
41324                     b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
41325                     a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
41326                     d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
41327                     c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
41328                     b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
41329                     a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
41330                     d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
41331                     c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
41332                     b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
41333                     a = safe_add(a, olda);
41334                     b = safe_add(b, oldb);
41335                     c = safe_add(c, oldc);
41336                     d = safe_add(d, oldd);
41337                   }
41338
41339                   return Array(a, b, c, d);
41340                 }
41341                 /**
41342                  * These functions implement the four basic operations the algorithm uses.
41343                  */
41344
41345
41346                 function md5_cmn(q, a, b, x, s, t) {
41347                   return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
41348                 }
41349
41350                 function md5_ff(a, b, c, d, x, s, t) {
41351                   return md5_cmn(b & c | ~b & d, a, b, x, s, t);
41352                 }
41353
41354                 function md5_gg(a, b, c, d, x, s, t) {
41355                   return md5_cmn(b & d | c & ~d, a, b, x, s, t);
41356                 }
41357
41358                 function md5_hh(a, b, c, d, x, s, t) {
41359                   return md5_cmn(b ^ c ^ d, a, b, x, s, t);
41360                 }
41361
41362                 function md5_ii(a, b, c, d, x, s, t) {
41363                   return md5_cmn(c ^ (b | ~d), a, b, x, s, t);
41364                 }
41365               },
41366
41367               /**
41368                * @member Hashes
41369                * @class Hashes.SHA1
41370                * @param {Object} [config]
41371                * @constructor
41372                *
41373                * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
41374                * Version 2.2 Copyright Paul Johnston 2000 - 2009.
41375                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41376                * See http://pajhome.org.uk/crypt/md5 for details.
41377                */
41378               SHA1: function SHA1(options) {
41379                 /**
41380                  * Private config properties. You may need to tweak these to be compatible with
41381                  * the server-side, but the defaults work in most cases.
41382                  * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
41383                  */
41384                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41385                     // hexadecimal output case format. false - lowercase; true - uppercase
41386                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41387                     // base-64 pad character. Defaults to '=' for strict RFC compliance
41388                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding
41389                 // public methods
41390
41391                 this.hex = function (s) {
41392                   return rstr2hex(rstr(s), hexcase);
41393                 };
41394
41395                 this.b64 = function (s) {
41396                   return rstr2b64(rstr(s), b64pad);
41397                 };
41398
41399                 this.any = function (s, e) {
41400                   return rstr2any(rstr(s), e);
41401                 };
41402
41403                 this.raw = function (s) {
41404                   return rstr(s);
41405                 };
41406
41407                 this.hex_hmac = function (k, d) {
41408                   return rstr2hex(rstr_hmac(k, d));
41409                 };
41410
41411                 this.b64_hmac = function (k, d) {
41412                   return rstr2b64(rstr_hmac(k, d), b64pad);
41413                 };
41414
41415                 this.any_hmac = function (k, d, e) {
41416                   return rstr2any(rstr_hmac(k, d), e);
41417                 };
41418                 /**
41419                  * Perform a simple self-test to see if the VM is working
41420                  * @return {String} Hexadecimal hash sample
41421                  * @public
41422                  */
41423
41424
41425                 this.vm_test = function () {
41426                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41427                 };
41428                 /**
41429                  * @description Enable/disable uppercase hexadecimal returned string
41430                  * @param {boolean}
41431                  * @return {Object} this
41432                  * @public
41433                  */
41434
41435
41436                 this.setUpperCase = function (a) {
41437                   if (typeof a === 'boolean') {
41438                     hexcase = a;
41439                   }
41440
41441                   return this;
41442                 };
41443                 /**
41444                  * @description Defines a base64 pad string
41445                  * @param {string} Pad
41446                  * @return {Object} this
41447                  * @public
41448                  */
41449
41450
41451                 this.setPad = function (a) {
41452                   b64pad = a || b64pad;
41453                   return this;
41454                 };
41455                 /**
41456                  * @description Defines a base64 pad string
41457                  * @param {boolean}
41458                  * @return {Object} this
41459                  * @public
41460                  */
41461
41462
41463                 this.setUTF8 = function (a) {
41464                   if (typeof a === 'boolean') {
41465                     utf8 = a;
41466                   }
41467
41468                   return this;
41469                 }; // private methods
41470
41471                 /**
41472                  * Calculate the SHA-512 of a raw string
41473                  */
41474
41475
41476                 function rstr(s) {
41477                   s = utf8 ? utf8Encode(s) : s;
41478                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
41479                 }
41480                 /**
41481                  * Calculate the HMAC-SHA1 of a key and some data (raw strings)
41482                  */
41483
41484
41485                 function rstr_hmac(key, data) {
41486                   var bkey, ipad, opad, i, hash;
41487                   key = utf8 ? utf8Encode(key) : key;
41488                   data = utf8 ? utf8Encode(data) : data;
41489                   bkey = rstr2binb(key);
41490
41491                   if (bkey.length > 16) {
41492                     bkey = binb(bkey, key.length * 8);
41493                   }
41494
41495                   ipad = Array(16), opad = Array(16);
41496
41497                   for (i = 0; i < 16; i += 1) {
41498                     ipad[i] = bkey[i] ^ 0x36363636;
41499                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
41500                   }
41501
41502                   hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
41503                   return binb2rstr(binb(opad.concat(hash), 512 + 160));
41504                 }
41505                 /**
41506                  * Calculate the SHA-1 of an array of big-endian words, and a bit length
41507                  */
41508
41509
41510                 function binb(x, len) {
41511                   var i,
41512                       j,
41513                       t,
41514                       olda,
41515                       oldb,
41516                       oldc,
41517                       oldd,
41518                       olde,
41519                       w = Array(80),
41520                       a = 1732584193,
41521                       b = -271733879,
41522                       c = -1732584194,
41523                       d = 271733878,
41524                       e = -1009589776;
41525                   /* append padding */
41526
41527                   x[len >> 5] |= 0x80 << 24 - len % 32;
41528                   x[(len + 64 >> 9 << 4) + 15] = len;
41529
41530                   for (i = 0; i < x.length; i += 16) {
41531                     olda = a;
41532                     oldb = b;
41533                     oldc = c;
41534                     oldd = d;
41535                     olde = e;
41536
41537                     for (j = 0; j < 80; j += 1) {
41538                       if (j < 16) {
41539                         w[j] = x[i + j];
41540                       } else {
41541                         w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
41542                       }
41543
41544                       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)));
41545                       e = d;
41546                       d = c;
41547                       c = bit_rol(b, 30);
41548                       b = a;
41549                       a = t;
41550                     }
41551
41552                     a = safe_add(a, olda);
41553                     b = safe_add(b, oldb);
41554                     c = safe_add(c, oldc);
41555                     d = safe_add(d, oldd);
41556                     e = safe_add(e, olde);
41557                   }
41558
41559                   return Array(a, b, c, d, e);
41560                 }
41561                 /**
41562                  * Perform the appropriate triplet combination function for the current
41563                  * iteration
41564                  */
41565
41566
41567                 function sha1_ft(t, b, c, d) {
41568                   if (t < 20) {
41569                     return b & c | ~b & d;
41570                   }
41571
41572                   if (t < 40) {
41573                     return b ^ c ^ d;
41574                   }
41575
41576                   if (t < 60) {
41577                     return b & c | b & d | c & d;
41578                   }
41579
41580                   return b ^ c ^ d;
41581                 }
41582                 /**
41583                  * Determine the appropriate additive constant for the current iteration
41584                  */
41585
41586
41587                 function sha1_kt(t) {
41588                   return t < 20 ? 1518500249 : t < 40 ? 1859775393 : t < 60 ? -1894007588 : -899497514;
41589                 }
41590               },
41591
41592               /**
41593                * @class Hashes.SHA256
41594                * @param {config}
41595                *
41596                * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
41597                * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
41598                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41599                * See http://pajhome.org.uk/crypt/md5 for details.
41600                * Also http://anmar.eu.org/projects/jssha2/
41601                */
41602               SHA256: function SHA256(options) {
41603                 /**
41604                  * Private properties configuration variables. You may need to tweak these to be compatible with
41605                  * the server-side, but the defaults work in most cases.
41606                  * @see this.setUpperCase() method
41607                  * @see this.setPad() method
41608                  */
41609                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41610                     // hexadecimal output case format. false - lowercase; true - uppercase  */
41611                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41612
41613                 /* base-64 pad character. Default '=' for strict RFC compliance   */
41614                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
41615
41616                 /* enable/disable utf8 encoding */
41617                 sha256_K;
41618                 /* privileged (public) methods */
41619
41620                 this.hex = function (s) {
41621                   return rstr2hex(rstr(s, utf8));
41622                 };
41623
41624                 this.b64 = function (s) {
41625                   return rstr2b64(rstr(s, utf8), b64pad);
41626                 };
41627
41628                 this.any = function (s, e) {
41629                   return rstr2any(rstr(s, utf8), e);
41630                 };
41631
41632                 this.raw = function (s) {
41633                   return rstr(s, utf8);
41634                 };
41635
41636                 this.hex_hmac = function (k, d) {
41637                   return rstr2hex(rstr_hmac(k, d));
41638                 };
41639
41640                 this.b64_hmac = function (k, d) {
41641                   return rstr2b64(rstr_hmac(k, d), b64pad);
41642                 };
41643
41644                 this.any_hmac = function (k, d, e) {
41645                   return rstr2any(rstr_hmac(k, d), e);
41646                 };
41647                 /**
41648                  * Perform a simple self-test to see if the VM is working
41649                  * @return {String} Hexadecimal hash sample
41650                  * @public
41651                  */
41652
41653
41654                 this.vm_test = function () {
41655                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41656                 };
41657                 /**
41658                  * Enable/disable uppercase hexadecimal returned string
41659                  * @param {boolean}
41660                  * @return {Object} this
41661                  * @public
41662                  */
41663
41664
41665                 this.setUpperCase = function (a) {
41666                   if (typeof a === 'boolean') {
41667                     hexcase = a;
41668                   }
41669
41670                   return this;
41671                 };
41672                 /**
41673                  * @description Defines a base64 pad string
41674                  * @param {string} Pad
41675                  * @return {Object} this
41676                  * @public
41677                  */
41678
41679
41680                 this.setPad = function (a) {
41681                   b64pad = a || b64pad;
41682                   return this;
41683                 };
41684                 /**
41685                  * Defines a base64 pad string
41686                  * @param {boolean}
41687                  * @return {Object} this
41688                  * @public
41689                  */
41690
41691
41692                 this.setUTF8 = function (a) {
41693                   if (typeof a === 'boolean') {
41694                     utf8 = a;
41695                   }
41696
41697                   return this;
41698                 }; // private methods
41699
41700                 /**
41701                  * Calculate the SHA-512 of a raw string
41702                  */
41703
41704
41705                 function rstr(s, utf8) {
41706                   s = utf8 ? utf8Encode(s) : s;
41707                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
41708                 }
41709                 /**
41710                  * Calculate the HMAC-sha256 of a key and some data (raw strings)
41711                  */
41712
41713
41714                 function rstr_hmac(key, data) {
41715                   key = utf8 ? utf8Encode(key) : key;
41716                   data = utf8 ? utf8Encode(data) : data;
41717                   var hash,
41718                       i = 0,
41719                       bkey = rstr2binb(key),
41720                       ipad = Array(16),
41721                       opad = Array(16);
41722
41723                   if (bkey.length > 16) {
41724                     bkey = binb(bkey, key.length * 8);
41725                   }
41726
41727                   for (; i < 16; i += 1) {
41728                     ipad[i] = bkey[i] ^ 0x36363636;
41729                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
41730                   }
41731
41732                   hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
41733                   return binb2rstr(binb(opad.concat(hash), 512 + 256));
41734                 }
41735                 /*
41736                  * Main sha256 function, with its support functions
41737                  */
41738
41739
41740                 function sha256_S(X, n) {
41741                   return X >>> n | X << 32 - n;
41742                 }
41743
41744                 function sha256_R(X, n) {
41745                   return X >>> n;
41746                 }
41747
41748                 function sha256_Ch(x, y, z) {
41749                   return x & y ^ ~x & z;
41750                 }
41751
41752                 function sha256_Maj(x, y, z) {
41753                   return x & y ^ x & z ^ y & z;
41754                 }
41755
41756                 function sha256_Sigma0256(x) {
41757                   return sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22);
41758                 }
41759
41760                 function sha256_Sigma1256(x) {
41761                   return sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25);
41762                 }
41763
41764                 function sha256_Gamma0256(x) {
41765                   return sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3);
41766                 }
41767
41768                 function sha256_Gamma1256(x) {
41769                   return sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10);
41770                 }
41771
41772                 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];
41773
41774                 function binb(m, l) {
41775                   var HASH = [1779033703, -1150833019, 1013904242, -1521486534, 1359893119, -1694144372, 528734635, 1541459225];
41776                   var W = new Array(64);
41777                   var a, b, c, d, e, f, g, h;
41778                   var i, j, T1, T2;
41779                   /* append padding */
41780
41781                   m[l >> 5] |= 0x80 << 24 - l % 32;
41782                   m[(l + 64 >> 9 << 4) + 15] = l;
41783
41784                   for (i = 0; i < m.length; i += 16) {
41785                     a = HASH[0];
41786                     b = HASH[1];
41787                     c = HASH[2];
41788                     d = HASH[3];
41789                     e = HASH[4];
41790                     f = HASH[5];
41791                     g = HASH[6];
41792                     h = HASH[7];
41793
41794                     for (j = 0; j < 64; j += 1) {
41795                       if (j < 16) {
41796                         W[j] = m[j + i];
41797                       } else {
41798                         W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]), sha256_Gamma0256(W[j - 15])), W[j - 16]);
41799                       }
41800
41801                       T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)), sha256_K[j]), W[j]);
41802                       T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
41803                       h = g;
41804                       g = f;
41805                       f = e;
41806                       e = safe_add(d, T1);
41807                       d = c;
41808                       c = b;
41809                       b = a;
41810                       a = safe_add(T1, T2);
41811                     }
41812
41813                     HASH[0] = safe_add(a, HASH[0]);
41814                     HASH[1] = safe_add(b, HASH[1]);
41815                     HASH[2] = safe_add(c, HASH[2]);
41816                     HASH[3] = safe_add(d, HASH[3]);
41817                     HASH[4] = safe_add(e, HASH[4]);
41818                     HASH[5] = safe_add(f, HASH[5]);
41819                     HASH[6] = safe_add(g, HASH[6]);
41820                     HASH[7] = safe_add(h, HASH[7]);
41821                   }
41822
41823                   return HASH;
41824                 }
41825               },
41826
41827               /**
41828                * @class Hashes.SHA512
41829                * @param {config}
41830                *
41831                * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
41832                * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
41833                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41834                * See http://pajhome.org.uk/crypt/md5 for details.
41835                */
41836               SHA512: function SHA512(options) {
41837                 /**
41838                  * Private properties configuration variables. You may need to tweak these to be compatible with
41839                  * the server-side, but the defaults work in most cases.
41840                  * @see this.setUpperCase() method
41841                  * @see this.setPad() method
41842                  */
41843                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41844
41845                 /* hexadecimal output case format. false - lowercase; true - uppercase  */
41846                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41847
41848                 /* base-64 pad character. Default '=' for strict RFC compliance   */
41849                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
41850
41851                 /* enable/disable utf8 encoding */
41852                 sha512_k;
41853                 /* privileged (public) methods */
41854
41855                 this.hex = function (s) {
41856                   return rstr2hex(rstr(s));
41857                 };
41858
41859                 this.b64 = function (s) {
41860                   return rstr2b64(rstr(s), b64pad);
41861                 };
41862
41863                 this.any = function (s, e) {
41864                   return rstr2any(rstr(s), e);
41865                 };
41866
41867                 this.raw = function (s) {
41868                   return rstr(s);
41869                 };
41870
41871                 this.hex_hmac = function (k, d) {
41872                   return rstr2hex(rstr_hmac(k, d));
41873                 };
41874
41875                 this.b64_hmac = function (k, d) {
41876                   return rstr2b64(rstr_hmac(k, d), b64pad);
41877                 };
41878
41879                 this.any_hmac = function (k, d, e) {
41880                   return rstr2any(rstr_hmac(k, d), e);
41881                 };
41882                 /**
41883                  * Perform a simple self-test to see if the VM is working
41884                  * @return {String} Hexadecimal hash sample
41885                  * @public
41886                  */
41887
41888
41889                 this.vm_test = function () {
41890                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41891                 };
41892                 /**
41893                  * @description Enable/disable uppercase hexadecimal returned string
41894                  * @param {boolean}
41895                  * @return {Object} this
41896                  * @public
41897                  */
41898
41899
41900                 this.setUpperCase = function (a) {
41901                   if (typeof a === 'boolean') {
41902                     hexcase = a;
41903                   }
41904
41905                   return this;
41906                 };
41907                 /**
41908                  * @description Defines a base64 pad string
41909                  * @param {string} Pad
41910                  * @return {Object} this
41911                  * @public
41912                  */
41913
41914
41915                 this.setPad = function (a) {
41916                   b64pad = a || b64pad;
41917                   return this;
41918                 };
41919                 /**
41920                  * @description Defines a base64 pad string
41921                  * @param {boolean}
41922                  * @return {Object} this
41923                  * @public
41924                  */
41925
41926
41927                 this.setUTF8 = function (a) {
41928                   if (typeof a === 'boolean') {
41929                     utf8 = a;
41930                   }
41931
41932                   return this;
41933                 };
41934                 /* private methods */
41935
41936                 /**
41937                  * Calculate the SHA-512 of a raw string
41938                  */
41939
41940
41941                 function rstr(s) {
41942                   s = utf8 ? utf8Encode(s) : s;
41943                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
41944                 }
41945                 /*
41946                  * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
41947                  */
41948
41949
41950                 function rstr_hmac(key, data) {
41951                   key = utf8 ? utf8Encode(key) : key;
41952                   data = utf8 ? utf8Encode(data) : data;
41953                   var hash,
41954                       i = 0,
41955                       bkey = rstr2binb(key),
41956                       ipad = Array(32),
41957                       opad = Array(32);
41958
41959                   if (bkey.length > 32) {
41960                     bkey = binb(bkey, key.length * 8);
41961                   }
41962
41963                   for (; i < 32; i += 1) {
41964                     ipad[i] = bkey[i] ^ 0x36363636;
41965                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
41966                   }
41967
41968                   hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
41969                   return binb2rstr(binb(opad.concat(hash), 1024 + 512));
41970                 }
41971                 /**
41972                  * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
41973                  */
41974
41975
41976                 function binb(x, len) {
41977                   var j,
41978                       i,
41979                       l,
41980                       W = new Array(80),
41981                       hash = new Array(16),
41982                       //Initial hash values
41983                   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)],
41984                       T1 = new int64(0, 0),
41985                       T2 = new int64(0, 0),
41986                       a = new int64(0, 0),
41987                       b = new int64(0, 0),
41988                       c = new int64(0, 0),
41989                       d = new int64(0, 0),
41990                       e = new int64(0, 0),
41991                       f = new int64(0, 0),
41992                       g = new int64(0, 0),
41993                       h = new int64(0, 0),
41994                       //Temporary variables not specified by the document
41995                   s0 = new int64(0, 0),
41996                       s1 = new int64(0, 0),
41997                       Ch = new int64(0, 0),
41998                       Maj = new int64(0, 0),
41999                       r1 = new int64(0, 0),
42000                       r2 = new int64(0, 0),
42001                       r3 = new int64(0, 0);
42002
42003                   if (sha512_k === undefined) {
42004                     //SHA512 constants
42005                     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)];
42006                   }
42007
42008                   for (i = 0; i < 80; i += 1) {
42009                     W[i] = new int64(0, 0);
42010                   } // append padding to the source string. The format is described in the FIPS.
42011
42012
42013                   x[len >> 5] |= 0x80 << 24 - (len & 0x1f);
42014                   x[(len + 128 >> 10 << 5) + 31] = len;
42015                   l = x.length;
42016
42017                   for (i = 0; i < l; i += 32) {
42018                     //32 dwords is the block size
42019                     int64copy(a, H[0]);
42020                     int64copy(b, H[1]);
42021                     int64copy(c, H[2]);
42022                     int64copy(d, H[3]);
42023                     int64copy(e, H[4]);
42024                     int64copy(f, H[5]);
42025                     int64copy(g, H[6]);
42026                     int64copy(h, H[7]);
42027
42028                     for (j = 0; j < 16; j += 1) {
42029                       W[j].h = x[i + 2 * j];
42030                       W[j].l = x[i + 2 * j + 1];
42031                     }
42032
42033                     for (j = 16; j < 80; j += 1) {
42034                       //sigma1
42035                       int64rrot(r1, W[j - 2], 19);
42036                       int64revrrot(r2, W[j - 2], 29);
42037                       int64shr(r3, W[j - 2], 6);
42038                       s1.l = r1.l ^ r2.l ^ r3.l;
42039                       s1.h = r1.h ^ r2.h ^ r3.h; //sigma0
42040
42041                       int64rrot(r1, W[j - 15], 1);
42042                       int64rrot(r2, W[j - 15], 8);
42043                       int64shr(r3, W[j - 15], 7);
42044                       s0.l = r1.l ^ r2.l ^ r3.l;
42045                       s0.h = r1.h ^ r2.h ^ r3.h;
42046                       int64add4(W[j], s1, W[j - 7], s0, W[j - 16]);
42047                     }
42048
42049                     for (j = 0; j < 80; j += 1) {
42050                       //Ch
42051                       Ch.l = e.l & f.l ^ ~e.l & g.l;
42052                       Ch.h = e.h & f.h ^ ~e.h & g.h; //Sigma1
42053
42054                       int64rrot(r1, e, 14);
42055                       int64rrot(r2, e, 18);
42056                       int64revrrot(r3, e, 9);
42057                       s1.l = r1.l ^ r2.l ^ r3.l;
42058                       s1.h = r1.h ^ r2.h ^ r3.h; //Sigma0
42059
42060                       int64rrot(r1, a, 28);
42061                       int64revrrot(r2, a, 2);
42062                       int64revrrot(r3, a, 7);
42063                       s0.l = r1.l ^ r2.l ^ r3.l;
42064                       s0.h = r1.h ^ r2.h ^ r3.h; //Maj
42065
42066                       Maj.l = a.l & b.l ^ a.l & c.l ^ b.l & c.l;
42067                       Maj.h = a.h & b.h ^ a.h & c.h ^ b.h & c.h;
42068                       int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
42069                       int64add(T2, s0, Maj);
42070                       int64copy(h, g);
42071                       int64copy(g, f);
42072                       int64copy(f, e);
42073                       int64add(e, d, T1);
42074                       int64copy(d, c);
42075                       int64copy(c, b);
42076                       int64copy(b, a);
42077                       int64add(a, T1, T2);
42078                     }
42079
42080                     int64add(H[0], H[0], a);
42081                     int64add(H[1], H[1], b);
42082                     int64add(H[2], H[2], c);
42083                     int64add(H[3], H[3], d);
42084                     int64add(H[4], H[4], e);
42085                     int64add(H[5], H[5], f);
42086                     int64add(H[6], H[6], g);
42087                     int64add(H[7], H[7], h);
42088                   } //represent the hash as an array of 32-bit dwords
42089
42090
42091                   for (i = 0; i < 8; i += 1) {
42092                     hash[2 * i] = H[i].h;
42093                     hash[2 * i + 1] = H[i].l;
42094                   }
42095
42096                   return hash;
42097                 } //A constructor for 64-bit numbers
42098
42099
42100                 function int64(h, l) {
42101                   this.h = h;
42102                   this.l = l; //this.toString = int64toString;
42103                 } //Copies src into dst, assuming both are 64-bit numbers
42104
42105
42106                 function int64copy(dst, src) {
42107                   dst.h = src.h;
42108                   dst.l = src.l;
42109                 } //Right-rotates a 64-bit number by shift
42110                 //Won't handle cases of shift>=32
42111                 //The function revrrot() is for that
42112
42113
42114                 function int64rrot(dst, x, shift) {
42115                   dst.l = x.l >>> shift | x.h << 32 - shift;
42116                   dst.h = x.h >>> shift | x.l << 32 - shift;
42117                 } //Reverses the dwords of the source and then rotates right by shift.
42118                 //This is equivalent to rotation by 32+shift
42119
42120
42121                 function int64revrrot(dst, x, shift) {
42122                   dst.l = x.h >>> shift | x.l << 32 - shift;
42123                   dst.h = x.l >>> shift | x.h << 32 - shift;
42124                 } //Bitwise-shifts right a 64-bit number by shift
42125                 //Won't handle shift>=32, but it's never needed in SHA512
42126
42127
42128                 function int64shr(dst, x, shift) {
42129                   dst.l = x.l >>> shift | x.h << 32 - shift;
42130                   dst.h = x.h >>> shift;
42131                 } //Adds two 64-bit numbers
42132                 //Like the original implementation, does not rely on 32-bit operations
42133
42134
42135                 function int64add(dst, x, y) {
42136                   var w0 = (x.l & 0xffff) + (y.l & 0xffff);
42137                   var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
42138                   var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
42139                   var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
42140                   dst.l = w0 & 0xffff | w1 << 16;
42141                   dst.h = w2 & 0xffff | w3 << 16;
42142                 } //Same, except with 4 addends. Works faster than adding them one by one.
42143
42144
42145                 function int64add4(dst, a, b, c, d) {
42146                   var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
42147                   var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
42148                   var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
42149                   var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
42150                   dst.l = w0 & 0xffff | w1 << 16;
42151                   dst.h = w2 & 0xffff | w3 << 16;
42152                 } //Same, except with 5 addends
42153
42154
42155                 function int64add5(dst, a, b, c, d, e) {
42156                   var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
42157                       w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
42158                       w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
42159                       w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
42160                   dst.l = w0 & 0xffff | w1 << 16;
42161                   dst.h = w2 & 0xffff | w3 << 16;
42162                 }
42163               },
42164
42165               /**
42166                * @class Hashes.RMD160
42167                * @constructor
42168                * @param {Object} [config]
42169                *
42170                * A JavaScript implementation of the RIPEMD-160 Algorithm
42171                * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
42172                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
42173                * See http://pajhome.org.uk/crypt/md5 for details.
42174                * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
42175                */
42176               RMD160: function RMD160(options) {
42177                 /**
42178                  * Private properties configuration variables. You may need to tweak these to be compatible with
42179                  * the server-side, but the defaults work in most cases.
42180                  * @see this.setUpperCase() method
42181                  * @see this.setPad() method
42182                  */
42183                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
42184
42185                 /* hexadecimal output case format. false - lowercase; true - uppercase  */
42186                 b64pad = options && typeof options.pad === 'string' ? options.pa : '=',
42187
42188                 /* base-64 pad character. Default '=' for strict RFC compliance   */
42189                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
42190
42191                 /* enable/disable utf8 encoding */
42192                 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],
42193                     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],
42194                     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],
42195                     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];
42196                 /* privileged (public) methods */
42197
42198                 this.hex = function (s) {
42199                   return rstr2hex(rstr(s));
42200                 };
42201
42202                 this.b64 = function (s) {
42203                   return rstr2b64(rstr(s), b64pad);
42204                 };
42205
42206                 this.any = function (s, e) {
42207                   return rstr2any(rstr(s), e);
42208                 };
42209
42210                 this.raw = function (s) {
42211                   return rstr(s);
42212                 };
42213
42214                 this.hex_hmac = function (k, d) {
42215                   return rstr2hex(rstr_hmac(k, d));
42216                 };
42217
42218                 this.b64_hmac = function (k, d) {
42219                   return rstr2b64(rstr_hmac(k, d), b64pad);
42220                 };
42221
42222                 this.any_hmac = function (k, d, e) {
42223                   return rstr2any(rstr_hmac(k, d), e);
42224                 };
42225                 /**
42226                  * Perform a simple self-test to see if the VM is working
42227                  * @return {String} Hexadecimal hash sample
42228                  * @public
42229                  */
42230
42231
42232                 this.vm_test = function () {
42233                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
42234                 };
42235                 /**
42236                  * @description Enable/disable uppercase hexadecimal returned string
42237                  * @param {boolean}
42238                  * @return {Object} this
42239                  * @public
42240                  */
42241
42242
42243                 this.setUpperCase = function (a) {
42244                   if (typeof a === 'boolean') {
42245                     hexcase = a;
42246                   }
42247
42248                   return this;
42249                 };
42250                 /**
42251                  * @description Defines a base64 pad string
42252                  * @param {string} Pad
42253                  * @return {Object} this
42254                  * @public
42255                  */
42256
42257
42258                 this.setPad = function (a) {
42259                   if (typeof a !== 'undefined') {
42260                     b64pad = a;
42261                   }
42262
42263                   return this;
42264                 };
42265                 /**
42266                  * @description Defines a base64 pad string
42267                  * @param {boolean}
42268                  * @return {Object} this
42269                  * @public
42270                  */
42271
42272
42273                 this.setUTF8 = function (a) {
42274                   if (typeof a === 'boolean') {
42275                     utf8 = a;
42276                   }
42277
42278                   return this;
42279                 };
42280                 /* private methods */
42281
42282                 /**
42283                  * Calculate the rmd160 of a raw string
42284                  */
42285
42286
42287                 function rstr(s) {
42288                   s = utf8 ? utf8Encode(s) : s;
42289                   return binl2rstr(binl(rstr2binl(s), s.length * 8));
42290                 }
42291                 /**
42292                  * Calculate the HMAC-rmd160 of a key and some data (raw strings)
42293                  */
42294
42295
42296                 function rstr_hmac(key, data) {
42297                   key = utf8 ? utf8Encode(key) : key;
42298                   data = utf8 ? utf8Encode(data) : data;
42299                   var i,
42300                       hash,
42301                       bkey = rstr2binl(key),
42302                       ipad = Array(16),
42303                       opad = Array(16);
42304
42305                   if (bkey.length > 16) {
42306                     bkey = binl(bkey, key.length * 8);
42307                   }
42308
42309                   for (i = 0; i < 16; i += 1) {
42310                     ipad[i] = bkey[i] ^ 0x36363636;
42311                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
42312                   }
42313
42314                   hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
42315                   return binl2rstr(binl(opad.concat(hash), 512 + 160));
42316                 }
42317                 /**
42318                  * Convert an array of little-endian words to a string
42319                  */
42320
42321
42322                 function binl2rstr(input) {
42323                   var i,
42324                       output = '',
42325                       l = input.length * 32;
42326
42327                   for (i = 0; i < l; i += 8) {
42328                     output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF);
42329                   }
42330
42331                   return output;
42332                 }
42333                 /**
42334                  * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
42335                  */
42336
42337
42338                 function binl(x, len) {
42339                   var T,
42340                       j,
42341                       i,
42342                       l,
42343                       h0 = 0x67452301,
42344                       h1 = 0xefcdab89,
42345                       h2 = 0x98badcfe,
42346                       h3 = 0x10325476,
42347                       h4 = 0xc3d2e1f0,
42348                       A1,
42349                       B1,
42350                       C1,
42351                       D1,
42352                       E1,
42353                       A2,
42354                       B2,
42355                       C2,
42356                       D2,
42357                       E2;
42358                   /* append padding */
42359
42360                   x[len >> 5] |= 0x80 << len % 32;
42361                   x[(len + 64 >>> 9 << 4) + 14] = len;
42362                   l = x.length;
42363
42364                   for (i = 0; i < l; i += 16) {
42365                     A1 = A2 = h0;
42366                     B1 = B2 = h1;
42367                     C1 = C2 = h2;
42368                     D1 = D2 = h3;
42369                     E1 = E2 = h4;
42370
42371                     for (j = 0; j <= 79; j += 1) {
42372                       T = safe_add(A1, rmd160_f(j, B1, C1, D1));
42373                       T = safe_add(T, x[i + rmd160_r1[j]]);
42374                       T = safe_add(T, rmd160_K1(j));
42375                       T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
42376                       A1 = E1;
42377                       E1 = D1;
42378                       D1 = bit_rol(C1, 10);
42379                       C1 = B1;
42380                       B1 = T;
42381                       T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
42382                       T = safe_add(T, x[i + rmd160_r2[j]]);
42383                       T = safe_add(T, rmd160_K2(j));
42384                       T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
42385                       A2 = E2;
42386                       E2 = D2;
42387                       D2 = bit_rol(C2, 10);
42388                       C2 = B2;
42389                       B2 = T;
42390                     }
42391
42392                     T = safe_add(h1, safe_add(C1, D2));
42393                     h1 = safe_add(h2, safe_add(D1, E2));
42394                     h2 = safe_add(h3, safe_add(E1, A2));
42395                     h3 = safe_add(h4, safe_add(A1, B2));
42396                     h4 = safe_add(h0, safe_add(B1, C2));
42397                     h0 = T;
42398                   }
42399
42400                   return [h0, h1, h2, h3, h4];
42401                 } // specific algorithm methods
42402
42403
42404                 function rmd160_f(j, x, y, z) {
42405                   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';
42406                 }
42407
42408                 function rmd160_K1(j) {
42409                   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';
42410                 }
42411
42412                 function rmd160_K2(j) {
42413                   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';
42414                 }
42415               }
42416             }; // exposes Hashes
42417
42418             (function (window, undefined$1) {
42419               var freeExports = false;
42420
42421               {
42422                 freeExports = exports;
42423
42424                 if (exports && _typeof(commonjsGlobal) === 'object' && commonjsGlobal && commonjsGlobal === commonjsGlobal.global) {
42425                   window = commonjsGlobal;
42426                 }
42427               }
42428
42429               if (typeof undefined$1 === 'function' && _typeof(undefined$1.amd) === 'object' && undefined$1.amd) {
42430                 // define as an anonymous module, so, through path mapping, it can be aliased
42431                 undefined$1(function () {
42432                   return Hashes;
42433                 });
42434               } else if (freeExports) {
42435                 // in Node.js or RingoJS v0.8.0+
42436                 if ( module && module.exports === freeExports) {
42437                   module.exports = Hashes;
42438                 } // in Narwhal or RingoJS v0.7.0-
42439                 else {
42440                     freeExports.Hashes = Hashes;
42441                   }
42442               } else {
42443                 // in a browser or Rhino
42444                 window.Hashes = Hashes;
42445               }
42446             })(this);
42447           })(); // IIFE
42448
42449         });
42450
42451         var immutable = extend$2;
42452         var hasOwnProperty$2 = Object.prototype.hasOwnProperty;
42453
42454         function extend$2() {
42455           var target = {};
42456
42457           for (var i = 0; i < arguments.length; i++) {
42458             var source = arguments[i];
42459
42460             for (var key in source) {
42461               if (hasOwnProperty$2.call(source, key)) {
42462                 target[key] = source[key];
42463               }
42464             }
42465           }
42466
42467           return target;
42468         }
42469
42470         var sha1 = new hashes.SHA1();
42471         var ohauth = {};
42472
42473         ohauth.qsString = function (obj) {
42474           return Object.keys(obj).sort().map(function (key) {
42475             return ohauth.percentEncode(key) + '=' + ohauth.percentEncode(obj[key]);
42476           }).join('&');
42477         };
42478
42479         ohauth.stringQs = function (str) {
42480           return str.split('&').filter(function (pair) {
42481             return pair !== '';
42482           }).reduce(function (obj, pair) {
42483             var parts = pair.split('=');
42484             obj[decodeURIComponent(parts[0])] = null === parts[1] ? '' : decodeURIComponent(parts[1]);
42485             return obj;
42486           }, {});
42487         };
42488
42489         ohauth.rawxhr = function (method, url, data, headers, callback) {
42490           var xhr = new XMLHttpRequest(),
42491               twoHundred = /^20\d$/;
42492
42493           xhr.onreadystatechange = function () {
42494             if (4 === xhr.readyState && 0 !== xhr.status) {
42495               if (twoHundred.test(xhr.status)) callback(null, xhr);else return callback(xhr, null);
42496             }
42497           };
42498
42499           xhr.onerror = function (e) {
42500             return callback(e, null);
42501           };
42502
42503           xhr.open(method, url, true);
42504
42505           for (var h in headers) {
42506             xhr.setRequestHeader(h, headers[h]);
42507           }
42508
42509           xhr.send(data);
42510           return xhr;
42511         };
42512
42513         ohauth.xhr = function (method, url, auth, data, options, callback) {
42514           var headers = options && options.header || {
42515             'Content-Type': 'application/x-www-form-urlencoded'
42516           };
42517           headers.Authorization = 'OAuth ' + ohauth.authHeader(auth);
42518           return ohauth.rawxhr(method, url, data, headers, callback);
42519         };
42520
42521         ohauth.nonce = function () {
42522           for (var o = ''; o.length < 6;) {
42523             o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
42524           }
42525
42526           return o;
42527         };
42528
42529         ohauth.authHeader = function (obj) {
42530           return Object.keys(obj).sort().map(function (key) {
42531             return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
42532           }).join(', ');
42533         };
42534
42535         ohauth.timestamp = function () {
42536           return ~~(+new Date() / 1000);
42537         };
42538
42539         ohauth.percentEncode = function (s) {
42540           return encodeURIComponent(s).replace(/\!/g, '%21').replace(/\'/g, '%27').replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
42541         };
42542
42543         ohauth.baseString = function (method, url, params) {
42544           if (params.oauth_signature) delete params.oauth_signature;
42545           return [method, ohauth.percentEncode(url), ohauth.percentEncode(ohauth.qsString(params))].join('&');
42546         };
42547
42548         ohauth.signature = function (oauth_secret, token_secret, baseString) {
42549           return sha1.b64_hmac(ohauth.percentEncode(oauth_secret) + '&' + ohauth.percentEncode(token_secret), baseString);
42550         };
42551         /**
42552          * Takes an options object for configuration (consumer_key,
42553          * consumer_secret, version, signature_method, token, token_secret)
42554          * and returns a function that generates the Authorization header
42555          * for given data.
42556          *
42557          * The returned function takes these parameters:
42558          * - method: GET/POST/...
42559          * - uri: full URI with protocol, port, path and query string
42560          * - extra_params: any extra parameters (that are passed in the POST data),
42561          *   can be an object or a from-urlencoded string.
42562          *
42563          * Returned function returns full OAuth header with "OAuth" string in it.
42564          */
42565
42566
42567         ohauth.headerGenerator = function (options) {
42568           options = options || {};
42569           var consumer_key = options.consumer_key || '',
42570               consumer_secret = options.consumer_secret || '',
42571               signature_method = options.signature_method || 'HMAC-SHA1',
42572               version = options.version || '1.0',
42573               token = options.token || '',
42574               token_secret = options.token_secret || '';
42575           return function (method, uri, extra_params) {
42576             method = method.toUpperCase();
42577
42578             if (typeof extra_params === 'string' && extra_params.length > 0) {
42579               extra_params = ohauth.stringQs(extra_params);
42580             }
42581
42582             var uri_parts = uri.split('?', 2),
42583                 base_uri = uri_parts[0];
42584             var query_params = uri_parts.length === 2 ? ohauth.stringQs(uri_parts[1]) : {};
42585             var oauth_params = {
42586               oauth_consumer_key: consumer_key,
42587               oauth_signature_method: signature_method,
42588               oauth_version: version,
42589               oauth_timestamp: ohauth.timestamp(),
42590               oauth_nonce: ohauth.nonce()
42591             };
42592             if (token) oauth_params.oauth_token = token;
42593             var all_params = immutable({}, oauth_params, query_params, extra_params),
42594                 base_str = ohauth.baseString(method, base_uri, all_params);
42595             oauth_params.oauth_signature = ohauth.signature(consumer_secret, token_secret, base_str);
42596             return 'OAuth ' + ohauth.authHeader(oauth_params);
42597           };
42598         };
42599
42600         var ohauth_1 = ohauth;
42601
42602         var resolveUrl$1 = createCommonjsModule(function (module, exports) {
42603           // Copyright 2014 Simon Lydell
42604           // X11 (“MIT”) Licensed. (See LICENSE.)
42605           void function (root, factory) {
42606             {
42607               module.exports = factory();
42608             }
42609           }(commonjsGlobal, function () {
42610             function resolveUrl()
42611             /* ...urls */
42612             {
42613               var numUrls = arguments.length;
42614
42615               if (numUrls === 0) {
42616                 throw new Error("resolveUrl requires at least one argument; got none.");
42617               }
42618
42619               var base = document.createElement("base");
42620               base.href = arguments[0];
42621
42622               if (numUrls === 1) {
42623                 return base.href;
42624               }
42625
42626               var head = document.getElementsByTagName("head")[0];
42627               head.insertBefore(base, head.firstChild);
42628               var a = document.createElement("a");
42629               var resolved;
42630
42631               for (var index = 1; index < numUrls; index++) {
42632                 a.href = arguments[index];
42633                 resolved = a.href;
42634                 base.href = resolved;
42635               }
42636
42637               head.removeChild(base);
42638               return resolved;
42639             }
42640
42641             return resolveUrl;
42642           });
42643         });
42644
42645         var assign = make_assign();
42646         var create$1 = make_create();
42647         var trim$3 = make_trim();
42648         var Global = typeof window !== 'undefined' ? window : commonjsGlobal;
42649         var util = {
42650           assign: assign,
42651           create: create$1,
42652           trim: trim$3,
42653           bind: bind$1,
42654           slice: slice$2,
42655           each: each,
42656           map: map$1,
42657           pluck: pluck,
42658           isList: isList,
42659           isFunction: isFunction,
42660           isObject: isObject$2,
42661           Global: Global
42662         };
42663
42664         function make_assign() {
42665           if (Object.assign) {
42666             return Object.assign;
42667           } else {
42668             return function shimAssign(obj, props1, props2, etc) {
42669               for (var i = 1; i < arguments.length; i++) {
42670                 each(Object(arguments[i]), function (val, key) {
42671                   obj[key] = val;
42672                 });
42673               }
42674
42675               return obj;
42676             };
42677           }
42678         }
42679
42680         function make_create() {
42681           if (Object.create) {
42682             return function create(obj, assignProps1, assignProps2, etc) {
42683               var assignArgsList = slice$2(arguments, 1);
42684               return assign.apply(this, [Object.create(obj)].concat(assignArgsList));
42685             };
42686           } else {
42687             var F = function F() {}; // eslint-disable-line no-inner-declarations
42688
42689
42690             return function create(obj, assignProps1, assignProps2, etc) {
42691               var assignArgsList = slice$2(arguments, 1);
42692               F.prototype = obj;
42693               return assign.apply(this, [new F()].concat(assignArgsList));
42694             };
42695           }
42696         }
42697
42698         function make_trim() {
42699           if (String.prototype.trim) {
42700             return function trim(str) {
42701               return String.prototype.trim.call(str);
42702             };
42703           } else {
42704             return function trim(str) {
42705               return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
42706             };
42707           }
42708         }
42709
42710         function bind$1(obj, fn) {
42711           return function () {
42712             return fn.apply(obj, Array.prototype.slice.call(arguments, 0));
42713           };
42714         }
42715
42716         function slice$2(arr, index) {
42717           return Array.prototype.slice.call(arr, index || 0);
42718         }
42719
42720         function each(obj, fn) {
42721           pluck(obj, function (val, key) {
42722             fn(val, key);
42723             return false;
42724           });
42725         }
42726
42727         function map$1(obj, fn) {
42728           var res = isList(obj) ? [] : {};
42729           pluck(obj, function (v, k) {
42730             res[k] = fn(v, k);
42731             return false;
42732           });
42733           return res;
42734         }
42735
42736         function pluck(obj, fn) {
42737           if (isList(obj)) {
42738             for (var i = 0; i < obj.length; i++) {
42739               if (fn(obj[i], i)) {
42740                 return obj[i];
42741               }
42742             }
42743           } else {
42744             for (var key in obj) {
42745               if (obj.hasOwnProperty(key)) {
42746                 if (fn(obj[key], key)) {
42747                   return obj[key];
42748                 }
42749               }
42750             }
42751           }
42752         }
42753
42754         function isList(val) {
42755           return val != null && typeof val != 'function' && typeof val.length == 'number';
42756         }
42757
42758         function isFunction(val) {
42759           return val && {}.toString.call(val) === '[object Function]';
42760         }
42761
42762         function isObject$2(val) {
42763           return val && {}.toString.call(val) === '[object Object]';
42764         }
42765
42766         var slice$3 = util.slice;
42767         var pluck$1 = util.pluck;
42768         var each$1 = util.each;
42769         var bind$2 = util.bind;
42770         var create$2 = util.create;
42771         var isList$1 = util.isList;
42772         var isFunction$1 = util.isFunction;
42773         var isObject$3 = util.isObject;
42774         var storeEngine = {
42775           createStore: _createStore
42776         };
42777         var storeAPI = {
42778           version: '2.0.12',
42779           enabled: false,
42780           // get returns the value of the given key. If that value
42781           // is undefined, it returns optionalDefaultValue instead.
42782           get: function get(key, optionalDefaultValue) {
42783             var data = this.storage.read(this._namespacePrefix + key);
42784             return this._deserialize(data, optionalDefaultValue);
42785           },
42786           // set will store the given value at key and returns value.
42787           // Calling set with value === undefined is equivalent to calling remove.
42788           set: function set(key, value) {
42789             if (value === undefined) {
42790               return this.remove(key);
42791             }
42792
42793             this.storage.write(this._namespacePrefix + key, this._serialize(value));
42794             return value;
42795           },
42796           // remove deletes the key and value stored at the given key.
42797           remove: function remove(key) {
42798             this.storage.remove(this._namespacePrefix + key);
42799           },
42800           // each will call the given callback once for each key-value pair
42801           // in this store.
42802           each: function each(callback) {
42803             var self = this;
42804             this.storage.each(function (val, namespacedKey) {
42805               callback.call(self, self._deserialize(val), (namespacedKey || '').replace(self._namespaceRegexp, ''));
42806             });
42807           },
42808           // clearAll will remove all the stored key-value pairs in this store.
42809           clearAll: function clearAll() {
42810             this.storage.clearAll();
42811           },
42812           // additional functionality that can't live in plugins
42813           // ---------------------------------------------------
42814           // hasNamespace returns true if this store instance has the given namespace.
42815           hasNamespace: function hasNamespace(namespace) {
42816             return this._namespacePrefix == '__storejs_' + namespace + '_';
42817           },
42818           // createStore creates a store.js instance with the first
42819           // functioning storage in the list of storage candidates,
42820           // and applies the the given mixins to the instance.
42821           createStore: function createStore() {
42822             return _createStore.apply(this, arguments);
42823           },
42824           addPlugin: function addPlugin(plugin) {
42825             this._addPlugin(plugin);
42826           },
42827           namespace: function namespace(_namespace) {
42828             return _createStore(this.storage, this.plugins, _namespace);
42829           }
42830         };
42831
42832         function _warn() {
42833           var _console = typeof console == 'undefined' ? null : console;
42834
42835           if (!_console) {
42836             return;
42837           }
42838
42839           var fn = _console.warn ? _console.warn : _console.log;
42840           fn.apply(_console, arguments);
42841         }
42842
42843         function _createStore(storages, plugins, namespace) {
42844           if (!namespace) {
42845             namespace = '';
42846           }
42847
42848           if (storages && !isList$1(storages)) {
42849             storages = [storages];
42850           }
42851
42852           if (plugins && !isList$1(plugins)) {
42853             plugins = [plugins];
42854           }
42855
42856           var namespacePrefix = namespace ? '__storejs_' + namespace + '_' : '';
42857           var namespaceRegexp = namespace ? new RegExp('^' + namespacePrefix) : null;
42858           var legalNamespaces = /^[a-zA-Z0-9_\-]*$/; // alpha-numeric + underscore and dash
42859
42860           if (!legalNamespaces.test(namespace)) {
42861             throw new Error('store.js namespaces can only have alphanumerics + underscores and dashes');
42862           }
42863
42864           var _privateStoreProps = {
42865             _namespacePrefix: namespacePrefix,
42866             _namespaceRegexp: namespaceRegexp,
42867             _testStorage: function _testStorage(storage) {
42868               try {
42869                 var testStr = '__storejs__test__';
42870                 storage.write(testStr, testStr);
42871                 var ok = storage.read(testStr) === testStr;
42872                 storage.remove(testStr);
42873                 return ok;
42874               } catch (e) {
42875                 return false;
42876               }
42877             },
42878             _assignPluginFnProp: function _assignPluginFnProp(pluginFnProp, propName) {
42879               var oldFn = this[propName];
42880
42881               this[propName] = function pluginFn() {
42882                 var args = slice$3(arguments, 0);
42883                 var self = this; // super_fn calls the old function which was overwritten by
42884                 // this mixin.
42885
42886                 function super_fn() {
42887                   if (!oldFn) {
42888                     return;
42889                   }
42890
42891                   each$1(arguments, function (arg, i) {
42892                     args[i] = arg;
42893                   });
42894                   return oldFn.apply(self, args);
42895                 } // Give mixing function access to super_fn by prefixing all mixin function
42896                 // arguments with super_fn.
42897
42898
42899                 var newFnArgs = [super_fn].concat(args);
42900                 return pluginFnProp.apply(self, newFnArgs);
42901               };
42902             },
42903             _serialize: function _serialize(obj) {
42904               return JSON.stringify(obj);
42905             },
42906             _deserialize: function _deserialize(strVal, defaultVal) {
42907               if (!strVal) {
42908                 return defaultVal;
42909               } // It is possible that a raw string value has been previously stored
42910               // in a storage without using store.js, meaning it will be a raw
42911               // string value instead of a JSON serialized string. By defaulting
42912               // to the raw string value in case of a JSON parse error, we allow
42913               // for past stored values to be forwards-compatible with store.js
42914
42915
42916               var val = '';
42917
42918               try {
42919                 val = JSON.parse(strVal);
42920               } catch (e) {
42921                 val = strVal;
42922               }
42923
42924               return val !== undefined ? val : defaultVal;
42925             },
42926             _addStorage: function _addStorage(storage) {
42927               if (this.enabled) {
42928                 return;
42929               }
42930
42931               if (this._testStorage(storage)) {
42932                 this.storage = storage;
42933                 this.enabled = true;
42934               }
42935             },
42936             _addPlugin: function _addPlugin(plugin) {
42937               var self = this; // If the plugin is an array, then add all plugins in the array.
42938               // This allows for a plugin to depend on other plugins.
42939
42940               if (isList$1(plugin)) {
42941                 each$1(plugin, function (plugin) {
42942                   self._addPlugin(plugin);
42943                 });
42944                 return;
42945               } // Keep track of all plugins we've seen so far, so that we
42946               // don't add any of them twice.
42947
42948
42949               var seenPlugin = pluck$1(this.plugins, function (seenPlugin) {
42950                 return plugin === seenPlugin;
42951               });
42952
42953               if (seenPlugin) {
42954                 return;
42955               }
42956
42957               this.plugins.push(plugin); // Check that the plugin is properly formed
42958
42959               if (!isFunction$1(plugin)) {
42960                 throw new Error('Plugins must be function values that return objects');
42961               }
42962
42963               var pluginProperties = plugin.call(this);
42964
42965               if (!isObject$3(pluginProperties)) {
42966                 throw new Error('Plugins must return an object of function properties');
42967               } // Add the plugin function properties to this store instance.
42968
42969
42970               each$1(pluginProperties, function (pluginFnProp, propName) {
42971                 if (!isFunction$1(pluginFnProp)) {
42972                   throw new Error('Bad plugin property: ' + propName + ' from plugin ' + plugin.name + '. Plugins should only return functions.');
42973                 }
42974
42975                 self._assignPluginFnProp(pluginFnProp, propName);
42976               });
42977             },
42978             // Put deprecated properties in the private API, so as to not expose it to accidential
42979             // discovery through inspection of the store object.
42980             // Deprecated: addStorage
42981             addStorage: function addStorage(storage) {
42982               _warn('store.addStorage(storage) is deprecated. Use createStore([storages])');
42983
42984               this._addStorage(storage);
42985             }
42986           };
42987           var store = create$2(_privateStoreProps, storeAPI, {
42988             plugins: []
42989           });
42990           store.raw = {};
42991           each$1(store, function (prop, propName) {
42992             if (isFunction$1(prop)) {
42993               store.raw[propName] = bind$2(store, prop);
42994             }
42995           });
42996           each$1(storages, function (storage) {
42997             store._addStorage(storage);
42998           });
42999           each$1(plugins, function (plugin) {
43000             store._addPlugin(plugin);
43001           });
43002           return store;
43003         }
43004
43005         var Global$1 = util.Global;
43006         var localStorage_1 = {
43007           name: 'localStorage',
43008           read: read,
43009           write: write,
43010           each: each$2,
43011           remove: remove$2,
43012           clearAll: clearAll
43013         };
43014
43015         function localStorage$1() {
43016           return Global$1.localStorage;
43017         }
43018
43019         function read(key) {
43020           return localStorage$1().getItem(key);
43021         }
43022
43023         function write(key, data) {
43024           return localStorage$1().setItem(key, data);
43025         }
43026
43027         function each$2(fn) {
43028           for (var i = localStorage$1().length - 1; i >= 0; i--) {
43029             var key = localStorage$1().key(i);
43030             fn(read(key), key);
43031           }
43032         }
43033
43034         function remove$2(key) {
43035           return localStorage$1().removeItem(key);
43036         }
43037
43038         function clearAll() {
43039           return localStorage$1().clear();
43040         }
43041
43042         // versions 6 and 7, where no localStorage, etc
43043         // is available.
43044
43045         var Global$2 = util.Global;
43046         var oldFFGlobalStorage = {
43047           name: 'oldFF-globalStorage',
43048           read: read$1,
43049           write: write$1,
43050           each: each$3,
43051           remove: remove$3,
43052           clearAll: clearAll$1
43053         };
43054         var globalStorage = Global$2.globalStorage;
43055
43056         function read$1(key) {
43057           return globalStorage[key];
43058         }
43059
43060         function write$1(key, data) {
43061           globalStorage[key] = data;
43062         }
43063
43064         function each$3(fn) {
43065           for (var i = globalStorage.length - 1; i >= 0; i--) {
43066             var key = globalStorage.key(i);
43067             fn(globalStorage[key], key);
43068           }
43069         }
43070
43071         function remove$3(key) {
43072           return globalStorage.removeItem(key);
43073         }
43074
43075         function clearAll$1() {
43076           each$3(function (key, _) {
43077             delete globalStorage[key];
43078           });
43079         }
43080
43081         // versions 6 and 7, where no localStorage, sessionStorage, etc
43082         // is available.
43083
43084         var Global$3 = util.Global;
43085         var oldIEUserDataStorage = {
43086           name: 'oldIE-userDataStorage',
43087           write: write$2,
43088           read: read$2,
43089           each: each$4,
43090           remove: remove$4,
43091           clearAll: clearAll$2
43092         };
43093         var storageName = 'storejs';
43094         var doc = Global$3.document;
43095
43096         var _withStorageEl = _makeIEStorageElFunction();
43097
43098         var disable = (Global$3.navigator ? Global$3.navigator.userAgent : '').match(/ (MSIE 8|MSIE 9|MSIE 10)\./); // MSIE 9.x, MSIE 10.x
43099
43100         function write$2(unfixedKey, data) {
43101           if (disable) {
43102             return;
43103           }
43104
43105           var fixedKey = fixKey(unfixedKey);
43106
43107           _withStorageEl(function (storageEl) {
43108             storageEl.setAttribute(fixedKey, data);
43109             storageEl.save(storageName);
43110           });
43111         }
43112
43113         function read$2(unfixedKey) {
43114           if (disable) {
43115             return;
43116           }
43117
43118           var fixedKey = fixKey(unfixedKey);
43119           var res = null;
43120
43121           _withStorageEl(function (storageEl) {
43122             res = storageEl.getAttribute(fixedKey);
43123           });
43124
43125           return res;
43126         }
43127
43128         function each$4(callback) {
43129           _withStorageEl(function (storageEl) {
43130             var attributes = storageEl.XMLDocument.documentElement.attributes;
43131
43132             for (var i = attributes.length - 1; i >= 0; i--) {
43133               var attr = attributes[i];
43134               callback(storageEl.getAttribute(attr.name), attr.name);
43135             }
43136           });
43137         }
43138
43139         function remove$4(unfixedKey) {
43140           var fixedKey = fixKey(unfixedKey);
43141
43142           _withStorageEl(function (storageEl) {
43143             storageEl.removeAttribute(fixedKey);
43144             storageEl.save(storageName);
43145           });
43146         }
43147
43148         function clearAll$2() {
43149           _withStorageEl(function (storageEl) {
43150             var attributes = storageEl.XMLDocument.documentElement.attributes;
43151             storageEl.load(storageName);
43152
43153             for (var i = attributes.length - 1; i >= 0; i--) {
43154               storageEl.removeAttribute(attributes[i].name);
43155             }
43156
43157             storageEl.save(storageName);
43158           });
43159         } // Helpers
43160         //////////
43161         // In IE7, keys cannot start with a digit or contain certain chars.
43162         // See https://github.com/marcuswestin/store.js/issues/40
43163         // See https://github.com/marcuswestin/store.js/issues/83
43164
43165
43166         var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g");
43167
43168         function fixKey(key) {
43169           return key.replace(/^\d/, '___$&').replace(forbiddenCharsRegex, '___');
43170         }
43171
43172         function _makeIEStorageElFunction() {
43173           if (!doc || !doc.documentElement || !doc.documentElement.addBehavior) {
43174             return null;
43175           }
43176
43177           var scriptTag = 'script',
43178               storageOwner,
43179               storageContainer,
43180               storageEl; // Since #userData storage applies only to specific paths, we need to
43181           // somehow link our data to a specific path.  We choose /favicon.ico
43182           // as a pretty safe option, since all browsers already make a request to
43183           // this URL anyway and being a 404 will not hurt us here.  We wrap an
43184           // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
43185           // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
43186           // since the iframe access rules appear to allow direct access and
43187           // manipulation of the document element, even for a 404 page.  This
43188           // document can be used instead of the current document (which would
43189           // have been limited to the current path) to perform #userData storage.
43190
43191           try {
43192             /* global ActiveXObject */
43193             storageContainer = new ActiveXObject('htmlfile');
43194             storageContainer.open();
43195             storageContainer.write('<' + scriptTag + '>document.w=window</' + scriptTag + '><iframe src="/favicon.ico"></iframe>');
43196             storageContainer.close();
43197             storageOwner = storageContainer.w.frames[0].document;
43198             storageEl = storageOwner.createElement('div');
43199           } catch (e) {
43200             // somehow ActiveXObject instantiation failed (perhaps some special
43201             // security settings or otherwse), fall back to per-path storage
43202             storageEl = doc.createElement('div');
43203             storageOwner = doc.body;
43204           }
43205
43206           return function (storeFunction) {
43207             var args = [].slice.call(arguments, 0);
43208             args.unshift(storageEl); // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
43209             // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
43210
43211             storageOwner.appendChild(storageEl);
43212             storageEl.addBehavior('#default#userData');
43213             storageEl.load(storageName);
43214             storeFunction.apply(this, args);
43215             storageOwner.removeChild(storageEl);
43216             return;
43217           };
43218         }
43219
43220         // doesn't work but cookies do. This implementation is adopted from
43221         // https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage
43222
43223         var Global$4 = util.Global;
43224         var trim$4 = util.trim;
43225         var cookieStorage = {
43226           name: 'cookieStorage',
43227           read: read$3,
43228           write: write$3,
43229           each: each$5,
43230           remove: remove$5,
43231           clearAll: clearAll$3
43232         };
43233         var doc$1 = Global$4.document;
43234
43235         function read$3(key) {
43236           if (!key || !_has(key)) {
43237             return null;
43238           }
43239
43240           var regexpStr = "(?:^|.*;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*";
43241           return unescape(doc$1.cookie.replace(new RegExp(regexpStr), "$1"));
43242         }
43243
43244         function each$5(callback) {
43245           var cookies = doc$1.cookie.split(/; ?/g);
43246
43247           for (var i = cookies.length - 1; i >= 0; i--) {
43248             if (!trim$4(cookies[i])) {
43249               continue;
43250             }
43251
43252             var kvp = cookies[i].split('=');
43253             var key = unescape(kvp[0]);
43254             var val = unescape(kvp[1]);
43255             callback(val, key);
43256           }
43257         }
43258
43259         function write$3(key, data) {
43260           if (!key) {
43261             return;
43262           }
43263
43264           doc$1.cookie = escape(key) + "=" + escape(data) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";
43265         }
43266
43267         function remove$5(key) {
43268           if (!key || !_has(key)) {
43269             return;
43270           }
43271
43272           doc$1.cookie = escape(key) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
43273         }
43274
43275         function clearAll$3() {
43276           each$5(function (_, key) {
43277             remove$5(key);
43278           });
43279         }
43280
43281         function _has(key) {
43282           return new RegExp("(?:^|;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=").test(doc$1.cookie);
43283         }
43284
43285         var Global$5 = util.Global;
43286         var sessionStorage_1 = {
43287           name: 'sessionStorage',
43288           read: read$4,
43289           write: write$4,
43290           each: each$6,
43291           remove: remove$6,
43292           clearAll: clearAll$4
43293         };
43294
43295         function sessionStorage() {
43296           return Global$5.sessionStorage;
43297         }
43298
43299         function read$4(key) {
43300           return sessionStorage().getItem(key);
43301         }
43302
43303         function write$4(key, data) {
43304           return sessionStorage().setItem(key, data);
43305         }
43306
43307         function each$6(fn) {
43308           for (var i = sessionStorage().length - 1; i >= 0; i--) {
43309             var key = sessionStorage().key(i);
43310             fn(read$4(key), key);
43311           }
43312         }
43313
43314         function remove$6(key) {
43315           return sessionStorage().removeItem(key);
43316         }
43317
43318         function clearAll$4() {
43319           return sessionStorage().clear();
43320         }
43321
43322         // memoryStorage is a useful last fallback to ensure that the store
43323         // is functions (meaning store.get(), store.set(), etc will all function).
43324         // However, stored values will not persist when the browser navigates to
43325         // a new page or reloads the current page.
43326         var memoryStorage_1 = {
43327           name: 'memoryStorage',
43328           read: read$5,
43329           write: write$5,
43330           each: each$7,
43331           remove: remove$7,
43332           clearAll: clearAll$5
43333         };
43334         var memoryStorage = {};
43335
43336         function read$5(key) {
43337           return memoryStorage[key];
43338         }
43339
43340         function write$5(key, data) {
43341           memoryStorage[key] = data;
43342         }
43343
43344         function each$7(callback) {
43345           for (var key in memoryStorage) {
43346             if (memoryStorage.hasOwnProperty(key)) {
43347               callback(memoryStorage[key], key);
43348             }
43349           }
43350         }
43351
43352         function remove$7(key) {
43353           delete memoryStorage[key];
43354         }
43355
43356         function clearAll$5(key) {
43357           memoryStorage = {};
43358         }
43359
43360         var all = [// Listed in order of usage preference
43361         localStorage_1, oldFFGlobalStorage, oldIEUserDataStorage, cookieStorage, sessionStorage_1, memoryStorage_1];
43362
43363         /* eslint-disable */
43364         //  json2.js
43365         //  2016-10-28
43366         //  Public Domain.
43367         //  NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
43368         //  See http://www.JSON.org/js.html
43369         //  This code should be minified before deployment.
43370         //  See http://javascript.crockford.com/jsmin.html
43371         //  USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
43372         //  NOT CONTROL.
43373         //  This file creates a global JSON object containing two methods: stringify
43374         //  and parse. This file provides the ES5 JSON capability to ES3 systems.
43375         //  If a project might run on IE8 or earlier, then this file should be included.
43376         //  This file does nothing on ES5 systems.
43377         //      JSON.stringify(value, replacer, space)
43378         //          value       any JavaScript value, usually an object or array.
43379         //          replacer    an optional parameter that determines how object
43380         //                      values are stringified for objects. It can be a
43381         //                      function or an array of strings.
43382         //          space       an optional parameter that specifies the indentation
43383         //                      of nested structures. If it is omitted, the text will
43384         //                      be packed without extra whitespace. If it is a number,
43385         //                      it will specify the number of spaces to indent at each
43386         //                      level. If it is a string (such as "\t" or "&nbsp;"),
43387         //                      it contains the characters used to indent at each level.
43388         //          This method produces a JSON text from a JavaScript value.
43389         //          When an object value is found, if the object contains a toJSON
43390         //          method, its toJSON method will be called and the result will be
43391         //          stringified. A toJSON method does not serialize: it returns the
43392         //          value represented by the name/value pair that should be serialized,
43393         //          or undefined if nothing should be serialized. The toJSON method
43394         //          will be passed the key associated with the value, and this will be
43395         //          bound to the value.
43396         //          For example, this would serialize Dates as ISO strings.
43397         //              Date.prototype.toJSON = function (key) {
43398         //                  function f(n) {
43399         //                      // Format integers to have at least two digits.
43400         //                      return (n < 10)
43401         //                          ? "0" + n
43402         //                          : n;
43403         //                  }
43404         //                  return this.getUTCFullYear()   + "-" +
43405         //                       f(this.getUTCMonth() + 1) + "-" +
43406         //                       f(this.getUTCDate())      + "T" +
43407         //                       f(this.getUTCHours())     + ":" +
43408         //                       f(this.getUTCMinutes())   + ":" +
43409         //                       f(this.getUTCSeconds())   + "Z";
43410         //              };
43411         //          You can provide an optional replacer method. It will be passed the
43412         //          key and value of each member, with this bound to the containing
43413         //          object. The value that is returned from your method will be
43414         //          serialized. If your method returns undefined, then the member will
43415         //          be excluded from the serialization.
43416         //          If the replacer parameter is an array of strings, then it will be
43417         //          used to select the members to be serialized. It filters the results
43418         //          such that only members with keys listed in the replacer array are
43419         //          stringified.
43420         //          Values that do not have JSON representations, such as undefined or
43421         //          functions, will not be serialized. Such values in objects will be
43422         //          dropped; in arrays they will be replaced with null. You can use
43423         //          a replacer function to replace those with JSON values.
43424         //          JSON.stringify(undefined) returns undefined.
43425         //          The optional space parameter produces a stringification of the
43426         //          value that is filled with line breaks and indentation to make it
43427         //          easier to read.
43428         //          If the space parameter is a non-empty string, then that string will
43429         //          be used for indentation. If the space parameter is a number, then
43430         //          the indentation will be that many spaces.
43431         //          Example:
43432         //          text = JSON.stringify(["e", {pluribus: "unum"}]);
43433         //          // text is '["e",{"pluribus":"unum"}]'
43434         //          text = JSON.stringify(["e", {pluribus: "unum"}], null, "\t");
43435         //          // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
43436         //          text = JSON.stringify([new Date()], function (key, value) {
43437         //              return this[key] instanceof Date
43438         //                  ? "Date(" + this[key] + ")"
43439         //                  : value;
43440         //          });
43441         //          // text is '["Date(---current time---)"]'
43442         //      JSON.parse(text, reviver)
43443         //          This method parses a JSON text to produce an object or array.
43444         //          It can throw a SyntaxError exception.
43445         //          The optional reviver parameter is a function that can filter and
43446         //          transform the results. It receives each of the keys and values,
43447         //          and its return value is used instead of the original value.
43448         //          If it returns what it received, then the structure is not modified.
43449         //          If it returns undefined then the member is deleted.
43450         //          Example:
43451         //          // Parse the text. Values that look like ISO date strings will
43452         //          // be converted to Date objects.
43453         //          myData = JSON.parse(text, function (key, value) {
43454         //              var a;
43455         //              if (typeof value === "string") {
43456         //                  a =
43457         //   /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
43458         //                  if (a) {
43459         //                      return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
43460         //                          +a[5], +a[6]));
43461         //                  }
43462         //              }
43463         //              return value;
43464         //          });
43465         //          myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
43466         //              var d;
43467         //              if (typeof value === "string" &&
43468         //                      value.slice(0, 5) === "Date(" &&
43469         //                      value.slice(-1) === ")") {
43470         //                  d = new Date(value.slice(5, -1));
43471         //                  if (d) {
43472         //                      return d;
43473         //                  }
43474         //              }
43475         //              return value;
43476         //          });
43477         //  This is a reference implementation. You are free to copy, modify, or
43478         //  redistribute.
43479
43480         /*jslint
43481             eval, for, this
43482         */
43483
43484         /*property
43485             JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
43486             getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
43487             lastIndex, length, parse, prototype, push, replace, slice, stringify,
43488             test, toJSON, toString, valueOf
43489         */
43490         // Create a JSON object only if one does not already exist. We create the
43491         // methods in a closure to avoid creating global variables.
43492         if ((typeof JSON === "undefined" ? "undefined" : _typeof(JSON)) !== "object") {
43493           JSON = {};
43494         }
43495
43496         (function () {
43497
43498           var rx_one = /^[\],:{}\s]*$/;
43499           var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
43500           var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
43501           var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
43502           var rx_escapable = /[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
43503           var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
43504
43505           function f(n) {
43506             // Format integers to have at least two digits.
43507             return n < 10 ? "0" + n : n;
43508           }
43509
43510           function this_value() {
43511             return this.valueOf();
43512           }
43513
43514           if (typeof Date.prototype.toJSON !== "function") {
43515             Date.prototype.toJSON = function () {
43516               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;
43517             };
43518
43519             Boolean.prototype.toJSON = this_value;
43520             Number.prototype.toJSON = this_value;
43521             String.prototype.toJSON = this_value;
43522           }
43523
43524           var gap;
43525           var indent;
43526           var meta;
43527           var rep;
43528
43529           function quote(string) {
43530             // If the string contains no control characters, no quote characters, and no
43531             // backslash characters, then we can safely slap some quotes around it.
43532             // Otherwise we must also replace the offending characters with safe escape
43533             // sequences.
43534             rx_escapable.lastIndex = 0;
43535             return rx_escapable.test(string) ? "\"" + string.replace(rx_escapable, function (a) {
43536               var c = meta[a];
43537               return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
43538             }) + "\"" : "\"" + string + "\"";
43539           }
43540
43541           function str(key, holder) {
43542             // Produce a string from holder[key].
43543             var i; // The loop counter.
43544
43545             var k; // The member key.
43546
43547             var v; // The member value.
43548
43549             var length;
43550             var mind = gap;
43551             var partial;
43552             var value = holder[key]; // If the value has a toJSON method, call it to obtain a replacement value.
43553
43554             if (value && _typeof(value) === "object" && typeof value.toJSON === "function") {
43555               value = value.toJSON(key);
43556             } // If we were called with a replacer function, then call the replacer to
43557             // obtain a replacement value.
43558
43559
43560             if (typeof rep === "function") {
43561               value = rep.call(holder, key, value);
43562             } // What happens next depends on the value's type.
43563
43564
43565             switch (_typeof(value)) {
43566               case "string":
43567                 return quote(value);
43568
43569               case "number":
43570                 // JSON numbers must be finite. Encode non-finite numbers as null.
43571                 return isFinite(value) ? String(value) : "null";
43572
43573               case "boolean":
43574               case "null":
43575                 // If the value is a boolean or null, convert it to a string. Note:
43576                 // typeof null does not produce "null". The case is included here in
43577                 // the remote chance that this gets fixed someday.
43578                 return String(value);
43579               // If the type is "object", we might be dealing with an object or an array or
43580               // null.
43581
43582               case "object":
43583                 // Due to a specification blunder in ECMAScript, typeof null is "object",
43584                 // so watch out for that case.
43585                 if (!value) {
43586                   return "null";
43587                 } // Make an array to hold the partial results of stringifying this object value.
43588
43589
43590                 gap += indent;
43591                 partial = []; // Is the value an array?
43592
43593                 if (Object.prototype.toString.apply(value) === "[object Array]") {
43594                   // The value is an array. Stringify every element. Use null as a placeholder
43595                   // for non-JSON values.
43596                   length = value.length;
43597
43598                   for (i = 0; i < length; i += 1) {
43599                     partial[i] = str(i, value) || "null";
43600                   } // Join all of the elements together, separated with commas, and wrap them in
43601                   // brackets.
43602
43603
43604                   v = partial.length === 0 ? "[]" : gap ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]" : "[" + partial.join(",") + "]";
43605                   gap = mind;
43606                   return v;
43607                 } // If the replacer is an array, use it to select the members to be stringified.
43608
43609
43610                 if (rep && _typeof(rep) === "object") {
43611                   length = rep.length;
43612
43613                   for (i = 0; i < length; i += 1) {
43614                     if (typeof rep[i] === "string") {
43615                       k = rep[i];
43616                       v = str(k, value);
43617
43618                       if (v) {
43619                         partial.push(quote(k) + (gap ? ": " : ":") + v);
43620                       }
43621                     }
43622                   }
43623                 } else {
43624                   // Otherwise, iterate through all of the keys in the object.
43625                   for (k in value) {
43626                     if (Object.prototype.hasOwnProperty.call(value, k)) {
43627                       v = str(k, value);
43628
43629                       if (v) {
43630                         partial.push(quote(k) + (gap ? ": " : ":") + v);
43631                       }
43632                     }
43633                   }
43634                 } // Join all of the member texts together, separated with commas,
43635                 // and wrap them in braces.
43636
43637
43638                 v = partial.length === 0 ? "{}" : gap ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}" : "{" + partial.join(",") + "}";
43639                 gap = mind;
43640                 return v;
43641             }
43642           } // If the JSON object does not yet have a stringify method, give it one.
43643
43644
43645           if (typeof JSON.stringify !== "function") {
43646             meta = {
43647               // table of character substitutions
43648               "\b": "\\b",
43649               "\t": "\\t",
43650               "\n": "\\n",
43651               "\f": "\\f",
43652               "\r": "\\r",
43653               "\"": "\\\"",
43654               "\\": "\\\\"
43655             };
43656
43657             JSON.stringify = function (value, replacer, space) {
43658               // The stringify method takes a value and an optional replacer, and an optional
43659               // space parameter, and returns a JSON text. The replacer can be a function
43660               // that can replace values, or an array of strings that will select the keys.
43661               // A default replacer method can be provided. Use of the space parameter can
43662               // produce text that is more easily readable.
43663               var i;
43664               gap = "";
43665               indent = ""; // If the space parameter is a number, make an indent string containing that
43666               // many spaces.
43667
43668               if (typeof space === "number") {
43669                 for (i = 0; i < space; i += 1) {
43670                   indent += " ";
43671                 } // If the space parameter is a string, it will be used as the indent string.
43672
43673               } else if (typeof space === "string") {
43674                 indent = space;
43675               } // If there is a replacer, it must be a function or an array.
43676               // Otherwise, throw an error.
43677
43678
43679               rep = replacer;
43680
43681               if (replacer && typeof replacer !== "function" && (_typeof(replacer) !== "object" || typeof replacer.length !== "number")) {
43682                 throw new Error("JSON.stringify");
43683               } // Make a fake root object containing our value under the key of "".
43684               // Return the result of stringifying the value.
43685
43686
43687               return str("", {
43688                 "": value
43689               });
43690             };
43691           } // If the JSON object does not yet have a parse method, give it one.
43692
43693
43694           if (typeof JSON.parse !== "function") {
43695             JSON.parse = function (text, reviver) {
43696               // The parse method takes a text and an optional reviver function, and returns
43697               // a JavaScript value if the text is a valid JSON text.
43698               var j;
43699
43700               function walk(holder, key) {
43701                 // The walk method is used to recursively walk the resulting structure so
43702                 // that modifications can be made.
43703                 var k;
43704                 var v;
43705                 var value = holder[key];
43706
43707                 if (value && _typeof(value) === "object") {
43708                   for (k in value) {
43709                     if (Object.prototype.hasOwnProperty.call(value, k)) {
43710                       v = walk(value, k);
43711
43712                       if (v !== undefined) {
43713                         value[k] = v;
43714                       } else {
43715                         delete value[k];
43716                       }
43717                     }
43718                   }
43719                 }
43720
43721                 return reviver.call(holder, key, value);
43722               } // Parsing happens in four stages. In the first stage, we replace certain
43723               // Unicode characters with escape sequences. JavaScript handles many characters
43724               // incorrectly, either silently deleting them, or treating them as line endings.
43725
43726
43727               text = String(text);
43728               rx_dangerous.lastIndex = 0;
43729
43730               if (rx_dangerous.test(text)) {
43731                 text = text.replace(rx_dangerous, function (a) {
43732                   return "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
43733                 });
43734               } // In the second stage, we run the text against regular expressions that look
43735               // for non-JSON patterns. We are especially concerned with "()" and "new"
43736               // because they can cause invocation, and "=" because it can cause mutation.
43737               // But just to be safe, we want to reject all unexpected forms.
43738               // We split the second stage into 4 regexp operations in order to work around
43739               // crippling inefficiencies in IE's and Safari's regexp engines. First we
43740               // replace the JSON backslash pairs with "@" (a non-JSON character). Second, we
43741               // replace all simple value tokens with "]" characters. Third, we delete all
43742               // open brackets that follow a colon or comma or that begin the text. Finally,
43743               // we look to see that the remaining characters are only whitespace or "]" or
43744               // "," or ":" or "{" or "}". If that is so, then the text is safe for eval.
43745
43746
43747               if (rx_one.test(text.replace(rx_two, "@").replace(rx_three, "]").replace(rx_four, ""))) {
43748                 // In the third stage we use the eval function to compile the text into a
43749                 // JavaScript structure. The "{" operator is subject to a syntactic ambiguity
43750                 // in JavaScript: it can begin a block or an object literal. We wrap the text
43751                 // in parens to eliminate the ambiguity.
43752                 j = eval("(" + text + ")"); // In the optional fourth stage, we recursively walk the new structure, passing
43753                 // each name/value pair to a reviver function for possible transformation.
43754
43755                 return typeof reviver === "function" ? walk({
43756                   "": j
43757                 }, "") : j;
43758               } // If the text is not JSON parseable, then a SyntaxError is thrown.
43759
43760
43761               throw new SyntaxError("JSON.parse");
43762             };
43763           }
43764         })();
43765
43766         var json2 = json2Plugin;
43767
43768         function json2Plugin() {
43769           return {};
43770         }
43771
43772         var plugins = [json2];
43773         var store_legacy = storeEngine.createStore(all, plugins);
43774
43775         //
43776         // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
43777         // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
43778         // does not support custom headers, which this uses everywhere.
43779
43780
43781         var osmAuth = function osmAuth(o) {
43782           var oauth = {}; // authenticated users will also have a request token secret, but it's
43783           // not used in transactions with the server
43784
43785           oauth.authenticated = function () {
43786             return !!(token('oauth_token') && token('oauth_token_secret'));
43787           };
43788
43789           oauth.logout = function () {
43790             token('oauth_token', '');
43791             token('oauth_token_secret', '');
43792             token('oauth_request_token_secret', '');
43793             return oauth;
43794           }; // TODO: detect lack of click event
43795
43796
43797           oauth.authenticate = function (callback) {
43798             if (oauth.authenticated()) return callback();
43799             oauth.logout(); // ## Getting a request token
43800
43801             var params = timenonce(getAuth(o)),
43802                 url = o.url + '/oauth/request_token';
43803             params.oauth_signature = ohauth_1.signature(o.oauth_secret, '', ohauth_1.baseString('POST', url, params));
43804
43805             if (!o.singlepage) {
43806               // Create a 600x550 popup window in the center of the screen
43807               var w = 600,
43808                   h = 550,
43809                   settings = [['width', w], ['height', h], ['left', screen.width / 2 - w / 2], ['top', screen.height / 2 - h / 2]].map(function (x) {
43810                 return x.join('=');
43811               }).join(','),
43812                   popup = window.open('about:blank', 'oauth_window', settings);
43813               oauth.popupWindow = popup;
43814
43815               if (!popup) {
43816                 var error = new Error('Popup was blocked');
43817                 error.status = 'popup-blocked';
43818                 throw error;
43819               }
43820             } // Request a request token. When this is complete, the popup
43821             // window is redirected to OSM's authorization page.
43822
43823
43824             ohauth_1.xhr('POST', url, params, null, {}, reqTokenDone);
43825             o.loading();
43826
43827             function reqTokenDone(err, xhr) {
43828               o.done();
43829               if (err) return callback(err);
43830               var resp = ohauth_1.stringQs(xhr.response);
43831               token('oauth_request_token_secret', resp.oauth_token_secret);
43832               var authorize_url = o.url + '/oauth/authorize?' + ohauth_1.qsString({
43833                 oauth_token: resp.oauth_token,
43834                 oauth_callback: resolveUrl$1(o.landing)
43835               });
43836
43837               if (o.singlepage) {
43838                 location.href = authorize_url;
43839               } else {
43840                 popup.location = authorize_url;
43841               }
43842             } // Called by a function in a landing page, in the popup window. The
43843             // window closes itself.
43844
43845
43846             window.authComplete = function (token) {
43847               var oauth_token = ohauth_1.stringQs(token.split('?')[1]);
43848               get_access_token(oauth_token.oauth_token);
43849               delete window.authComplete;
43850             }; // ## Getting an request token
43851             //
43852             // At this point we have an `oauth_token`, brought in from a function
43853             // call on a landing page popup.
43854
43855
43856             function get_access_token(oauth_token) {
43857               var url = o.url + '/oauth/access_token',
43858                   params = timenonce(getAuth(o)),
43859                   request_token_secret = token('oauth_request_token_secret');
43860               params.oauth_token = oauth_token;
43861               params.oauth_signature = ohauth_1.signature(o.oauth_secret, request_token_secret, ohauth_1.baseString('POST', url, params)); // ## Getting an access token
43862               //
43863               // The final token required for authentication. At this point
43864               // we have a `request token secret`
43865
43866               ohauth_1.xhr('POST', url, params, null, {}, accessTokenDone);
43867               o.loading();
43868             }
43869
43870             function accessTokenDone(err, xhr) {
43871               o.done();
43872               if (err) return callback(err);
43873               var access_token = ohauth_1.stringQs(xhr.response);
43874               token('oauth_token', access_token.oauth_token);
43875               token('oauth_token_secret', access_token.oauth_token_secret);
43876               callback(null, oauth);
43877             }
43878           };
43879
43880           oauth.bringPopupWindowToFront = function () {
43881             var brougtPopupToFront = false;
43882
43883             try {
43884               // This may cause a cross-origin error:
43885               // `DOMException: Blocked a frame with origin "..." from accessing a cross-origin frame.`
43886               if (oauth.popupWindow && !oauth.popupWindow.closed) {
43887                 oauth.popupWindow.focus();
43888                 brougtPopupToFront = true;
43889               }
43890             } catch (err) {// Bringing popup window to front failed (probably because of the cross-origin error mentioned above)
43891             }
43892
43893             return brougtPopupToFront;
43894           };
43895
43896           oauth.bootstrapToken = function (oauth_token, callback) {
43897             // ## Getting an request token
43898             // At this point we have an `oauth_token`, brought in from a function
43899             // call on a landing page popup.
43900             function get_access_token(oauth_token) {
43901               var url = o.url + '/oauth/access_token',
43902                   params = timenonce(getAuth(o)),
43903                   request_token_secret = token('oauth_request_token_secret');
43904               params.oauth_token = oauth_token;
43905               params.oauth_signature = ohauth_1.signature(o.oauth_secret, request_token_secret, ohauth_1.baseString('POST', url, params)); // ## Getting an access token
43906               // The final token required for authentication. At this point
43907               // we have a `request token secret`
43908
43909               ohauth_1.xhr('POST', url, params, null, {}, accessTokenDone);
43910               o.loading();
43911             }
43912
43913             function accessTokenDone(err, xhr) {
43914               o.done();
43915               if (err) return callback(err);
43916               var access_token = ohauth_1.stringQs(xhr.response);
43917               token('oauth_token', access_token.oauth_token);
43918               token('oauth_token_secret', access_token.oauth_token_secret);
43919               callback(null, oauth);
43920             }
43921
43922             get_access_token(oauth_token);
43923           }; // # xhr
43924           //
43925           // A single XMLHttpRequest wrapper that does authenticated calls if the
43926           // user has logged in.
43927
43928
43929           oauth.xhr = function (options, callback) {
43930             if (!oauth.authenticated()) {
43931               if (o.auto) {
43932                 return oauth.authenticate(run);
43933               } else {
43934                 callback('not authenticated', null);
43935                 return;
43936               }
43937             } else {
43938               return run();
43939             }
43940
43941             function run() {
43942               var params = timenonce(getAuth(o)),
43943                   oauth_token_secret = token('oauth_token_secret'),
43944                   url = options.prefix !== false ? o.url + options.path : options.path,
43945                   url_parts = url.replace(/#.*$/, '').split('?', 2),
43946                   base_url = url_parts[0],
43947                   query = url_parts.length === 2 ? url_parts[1] : ''; // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
43948
43949               if ((!options.options || !options.options.header || options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') && options.content) {
43950                 params = immutable(params, ohauth_1.stringQs(options.content));
43951               }
43952
43953               params.oauth_token = token('oauth_token');
43954               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))));
43955               return ohauth_1.xhr(options.method, url, params, options.content, options.options, done);
43956             }
43957
43958             function done(err, xhr) {
43959               if (err) return callback(err);else if (xhr.responseXML) return callback(err, xhr.responseXML);else return callback(err, xhr.response);
43960             }
43961           }; // pre-authorize this object, if we can just get a token and token_secret
43962           // from the start
43963
43964
43965           oauth.preauth = function (c) {
43966             if (!c) return;
43967             if (c.oauth_token) token('oauth_token', c.oauth_token);
43968             if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
43969             return oauth;
43970           };
43971
43972           oauth.options = function (_) {
43973             if (!arguments.length) return o;
43974             o = _;
43975             o.url = o.url || 'https://www.openstreetmap.org';
43976             o.landing = o.landing || 'land.html';
43977             o.singlepage = o.singlepage || false; // Optional loading and loading-done functions for nice UI feedback.
43978             // by default, no-ops
43979
43980             o.loading = o.loading || function () {};
43981
43982             o.done = o.done || function () {};
43983
43984             return oauth.preauth(o);
43985           }; // 'stamp' an authentication object from `getAuth()`
43986           // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
43987           // and timestamp
43988
43989
43990           function timenonce(o) {
43991             o.oauth_timestamp = ohauth_1.timestamp();
43992             o.oauth_nonce = ohauth_1.nonce();
43993             return o;
43994           } // get/set tokens. These are prefixed with the base URL so that `osm-auth`
43995           // can be used with multiple APIs and the keys in `localStorage`
43996           // will not clash
43997
43998
43999           var token;
44000
44001           if (store_legacy.enabled) {
44002             token = function token(x, y) {
44003               if (arguments.length === 1) return store_legacy.get(o.url + x);else if (arguments.length === 2) return store_legacy.set(o.url + x, y);
44004             };
44005           } else {
44006             var storage = {};
44007
44008             token = function token(x, y) {
44009               if (arguments.length === 1) return storage[o.url + x];else if (arguments.length === 2) return storage[o.url + x] = y;
44010             };
44011           } // Get an authentication object. If you just add and remove properties
44012           // from a single object, you'll need to use `delete` to make sure that
44013           // it doesn't contain undesired properties for authentication
44014
44015
44016           function getAuth(o) {
44017             return {
44018               oauth_consumer_key: o.oauth_consumer_key,
44019               oauth_signature_method: 'HMAC-SHA1'
44020             };
44021           } // potentially pre-authorize
44022
44023
44024           oauth.options(o);
44025           return oauth;
44026         };
44027
44028         var JXON = new function () {
44029           var sValueProp = 'keyValue',
44030               sAttributesProp = 'keyAttributes',
44031               sAttrPref = '@',
44032
44033           /* you can customize these values */
44034           aCache = [],
44035               rIsNull = /^\s*$/,
44036               rIsBool = /^(?:true|false)$/i;
44037
44038           function parseText(sValue) {
44039             if (rIsNull.test(sValue)) {
44040               return null;
44041             }
44042
44043             if (rIsBool.test(sValue)) {
44044               return sValue.toLowerCase() === 'true';
44045             }
44046
44047             if (isFinite(sValue)) {
44048               return parseFloat(sValue);
44049             }
44050
44051             if (isFinite(Date.parse(sValue))) {
44052               return new Date(sValue);
44053             }
44054
44055             return sValue;
44056           }
44057
44058           function EmptyTree() {}
44059
44060           EmptyTree.prototype.toString = function () {
44061             return 'null';
44062           };
44063
44064           EmptyTree.prototype.valueOf = function () {
44065             return null;
44066           };
44067
44068           function objectify(vValue) {
44069             return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
44070           }
44071
44072           function createObjTree(oParentNode, nVerb, bFreeze, bNesteAttr) {
44073             var nLevelStart = aCache.length,
44074                 bChildren = oParentNode.hasChildNodes(),
44075                 bAttributes = oParentNode.hasAttributes(),
44076                 bHighVerb = Boolean(nVerb & 2);
44077             var sProp,
44078                 vContent,
44079                 nLength = 0,
44080                 sCollectedTxt = '',
44081                 vResult = bHighVerb ? {} :
44082             /* put here the default value for empty nodes: */
44083             true;
44084
44085             if (bChildren) {
44086               for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
44087                 oNode = oParentNode.childNodes.item(nItem);
44088
44089                 if (oNode.nodeType === 4) {
44090                   sCollectedTxt += oNode.nodeValue;
44091                 }
44092                 /* nodeType is 'CDATASection' (4) */
44093                 else if (oNode.nodeType === 3) {
44094                     sCollectedTxt += oNode.nodeValue.trim();
44095                   }
44096                   /* nodeType is 'Text' (3) */
44097                   else if (oNode.nodeType === 1 && !oNode.prefix) {
44098                       aCache.push(oNode);
44099                     }
44100                 /* nodeType is 'Element' (1) */
44101
44102               }
44103             }
44104
44105             var nLevelEnd = aCache.length,
44106                 vBuiltVal = parseText(sCollectedTxt);
44107
44108             if (!bHighVerb && (bChildren || bAttributes)) {
44109               vResult = nVerb === 0 ? objectify(vBuiltVal) : {};
44110             }
44111
44112             for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
44113               sProp = aCache[nElId].nodeName.toLowerCase();
44114               vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
44115
44116               if (vResult.hasOwnProperty(sProp)) {
44117                 if (vResult[sProp].constructor !== Array) {
44118                   vResult[sProp] = [vResult[sProp]];
44119                 }
44120
44121                 vResult[sProp].push(vContent);
44122               } else {
44123                 vResult[sProp] = vContent;
44124                 nLength++;
44125               }
44126             }
44127
44128             if (bAttributes) {
44129               var nAttrLen = oParentNode.attributes.length,
44130                   sAPrefix = bNesteAttr ? '' : sAttrPref,
44131                   oAttrParent = bNesteAttr ? {} : vResult;
44132
44133               for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
44134                 oAttrib = oParentNode.attributes.item(nAttrib);
44135                 oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
44136               }
44137
44138               if (bNesteAttr) {
44139                 if (bFreeze) {
44140                   Object.freeze(oAttrParent);
44141                 }
44142
44143                 vResult[sAttributesProp] = oAttrParent;
44144                 nLength -= nAttrLen - 1;
44145               }
44146             }
44147
44148             if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
44149               vResult[sValueProp] = vBuiltVal;
44150             } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
44151               vResult = vBuiltVal;
44152             }
44153
44154             if (bFreeze && (bHighVerb || nLength > 0)) {
44155               Object.freeze(vResult);
44156             }
44157
44158             aCache.length = nLevelStart;
44159             return vResult;
44160           }
44161
44162           function loadObjTree(oXMLDoc, oParentEl, oParentObj) {
44163             var vValue, oChild;
44164
44165             if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
44166               oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString()));
44167               /* verbosity level is 0 */
44168             } else if (oParentObj.constructor === Date) {
44169               oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
44170             }
44171
44172             for (var sName in oParentObj) {
44173               vValue = oParentObj[sName];
44174
44175               if (isFinite(sName) || vValue instanceof Function) {
44176                 continue;
44177               }
44178               /* verbosity level is 0 */
44179
44180
44181               if (sName === sValueProp) {
44182                 if (vValue !== null && vValue !== true) {
44183                   oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue)));
44184                 }
44185               } else if (sName === sAttributesProp) {
44186                 /* verbosity level is 3 */
44187                 for (var sAttrib in vValue) {
44188                   oParentEl.setAttribute(sAttrib, vValue[sAttrib]);
44189                 }
44190               } else if (sName.charAt(0) === sAttrPref) {
44191                 oParentEl.setAttribute(sName.slice(1), vValue);
44192               } else if (vValue.constructor === Array) {
44193                 for (var nItem = 0; nItem < vValue.length; nItem++) {
44194                   oChild = oXMLDoc.createElement(sName);
44195                   loadObjTree(oXMLDoc, oChild, vValue[nItem]);
44196                   oParentEl.appendChild(oChild);
44197                 }
44198               } else {
44199                 oChild = oXMLDoc.createElement(sName);
44200
44201                 if (vValue instanceof Object) {
44202                   loadObjTree(oXMLDoc, oChild, vValue);
44203                 } else if (vValue !== null && vValue !== true) {
44204                   oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
44205                 }
44206
44207                 oParentEl.appendChild(oChild);
44208               }
44209             }
44210           }
44211
44212           this.build = function (oXMLParent, nVerbosity
44213           /* optional */
44214           , bFreeze
44215           /* optional */
44216           , bNesteAttributes
44217           /* optional */
44218           ) {
44219             var _nVerb = arguments.length > 1 && typeof nVerbosity === 'number' ? nVerbosity & 3 :
44220             /* put here the default verbosity level: */
44221             1;
44222
44223             return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
44224           };
44225
44226           this.unbuild = function (oObjTree) {
44227             var oNewDoc = document.implementation.createDocument('', '', null);
44228             loadObjTree(oNewDoc, oNewDoc, oObjTree);
44229             return oNewDoc;
44230           };
44231
44232           this.stringify = function (oObjTree) {
44233             return new XMLSerializer().serializeToString(JXON.unbuild(oObjTree));
44234           };
44235         }(); // var myObject = JXON.build(doc);
44236         // we got our javascript object! try: alert(JSON.stringify(myObject));
44237         // var newDoc = JXON.unbuild(myObject);
44238         // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
44239
44240         var tiler$5 = utilTiler();
44241         var dispatch$6 = dispatch('apiStatusChange', 'authLoading', 'authDone', 'change', 'loading', 'loaded', 'loadedNotes');
44242         var urlroot = 'https://www.openstreetmap.org';
44243         var oauth = osmAuth({
44244           url: urlroot,
44245           oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
44246           oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
44247           loading: authLoading,
44248           done: authDone
44249         }); // hardcode default block of Google Maps
44250
44251         var _imageryBlocklists = [/.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/];
44252         var _tileCache = {
44253           toLoad: {},
44254           loaded: {},
44255           inflight: {},
44256           seen: {},
44257           rtree: new RBush()
44258         };
44259         var _noteCache = {
44260           toLoad: {},
44261           loaded: {},
44262           inflight: {},
44263           inflightPost: {},
44264           note: {},
44265           closed: {},
44266           rtree: new RBush()
44267         };
44268         var _userCache = {
44269           toLoad: {},
44270           user: {}
44271         };
44272
44273         var _cachedApiStatus;
44274
44275         var _changeset = {};
44276
44277         var _deferred = new Set();
44278
44279         var _connectionID = 1;
44280         var _tileZoom$3 = 16;
44281         var _noteZoom = 12;
44282
44283         var _rateLimitError;
44284
44285         var _userChangesets;
44286
44287         var _userDetails;
44288
44289         var _off; // set a default but also load this from the API status
44290
44291
44292         var _maxWayNodes = 2000;
44293
44294         function authLoading() {
44295           dispatch$6.call('authLoading');
44296         }
44297
44298         function authDone() {
44299           dispatch$6.call('authDone');
44300         }
44301
44302         function abortRequest$5(controllerOrXHR) {
44303           if (controllerOrXHR) {
44304             controllerOrXHR.abort();
44305           }
44306         }
44307
44308         function hasInflightRequests(cache) {
44309           return Object.keys(cache.inflight).length;
44310         }
44311
44312         function abortUnwantedRequests$3(cache, visibleTiles) {
44313           Object.keys(cache.inflight).forEach(function (k) {
44314             if (cache.toLoad[k]) return;
44315             if (visibleTiles.find(function (tile) {
44316               return k === tile.id;
44317             })) return;
44318             abortRequest$5(cache.inflight[k]);
44319             delete cache.inflight[k];
44320           });
44321         }
44322
44323         function getLoc(attrs) {
44324           var lon = attrs.lon && attrs.lon.value;
44325           var lat = attrs.lat && attrs.lat.value;
44326           return [parseFloat(lon), parseFloat(lat)];
44327         }
44328
44329         function getNodes(obj) {
44330           var elems = obj.getElementsByTagName('nd');
44331           var nodes = new Array(elems.length);
44332
44333           for (var i = 0, l = elems.length; i < l; i++) {
44334             nodes[i] = 'n' + elems[i].attributes.ref.value;
44335           }
44336
44337           return nodes;
44338         }
44339
44340         function getNodesJSON(obj) {
44341           var elems = obj.nodes;
44342           var nodes = new Array(elems.length);
44343
44344           for (var i = 0, l = elems.length; i < l; i++) {
44345             nodes[i] = 'n' + elems[i];
44346           }
44347
44348           return nodes;
44349         }
44350
44351         function getTags(obj) {
44352           var elems = obj.getElementsByTagName('tag');
44353           var tags = {};
44354
44355           for (var i = 0, l = elems.length; i < l; i++) {
44356             var attrs = elems[i].attributes;
44357             tags[attrs.k.value] = attrs.v.value;
44358           }
44359
44360           return tags;
44361         }
44362
44363         function getMembers(obj) {
44364           var elems = obj.getElementsByTagName('member');
44365           var members = new Array(elems.length);
44366
44367           for (var i = 0, l = elems.length; i < l; i++) {
44368             var attrs = elems[i].attributes;
44369             members[i] = {
44370               id: attrs.type.value[0] + attrs.ref.value,
44371               type: attrs.type.value,
44372               role: attrs.role.value
44373             };
44374           }
44375
44376           return members;
44377         }
44378
44379         function getMembersJSON(obj) {
44380           var elems = obj.members;
44381           var members = new Array(elems.length);
44382
44383           for (var i = 0, l = elems.length; i < l; i++) {
44384             var attrs = elems[i];
44385             members[i] = {
44386               id: attrs.type[0] + attrs.ref,
44387               type: attrs.type,
44388               role: attrs.role
44389             };
44390           }
44391
44392           return members;
44393         }
44394
44395         function getVisible(attrs) {
44396           return !attrs.visible || attrs.visible.value !== 'false';
44397         }
44398
44399         function parseComments(comments) {
44400           var parsedComments = []; // for each comment
44401
44402           for (var i = 0; i < comments.length; i++) {
44403             var comment = comments[i];
44404
44405             if (comment.nodeName === 'comment') {
44406               var childNodes = comment.childNodes;
44407               var parsedComment = {};
44408
44409               for (var j = 0; j < childNodes.length; j++) {
44410                 var node = childNodes[j];
44411                 var nodeName = node.nodeName;
44412                 if (nodeName === '#text') continue;
44413                 parsedComment[nodeName] = node.textContent;
44414
44415                 if (nodeName === 'uid') {
44416                   var uid = node.textContent;
44417
44418                   if (uid && !_userCache.user[uid]) {
44419                     _userCache.toLoad[uid] = true;
44420                   }
44421                 }
44422               }
44423
44424               if (parsedComment) {
44425                 parsedComments.push(parsedComment);
44426               }
44427             }
44428           }
44429
44430           return parsedComments;
44431         }
44432
44433         function encodeNoteRtree(note) {
44434           return {
44435             minX: note.loc[0],
44436             minY: note.loc[1],
44437             maxX: note.loc[0],
44438             maxY: note.loc[1],
44439             data: note
44440           };
44441         }
44442
44443         var jsonparsers = {
44444           node: function nodeData(obj, uid) {
44445             return new osmNode({
44446               id: uid,
44447               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
44448               version: obj.version && obj.version.toString(),
44449               changeset: obj.changeset && obj.changeset.toString(),
44450               timestamp: obj.timestamp,
44451               user: obj.user,
44452               uid: obj.uid && obj.uid.toString(),
44453               loc: [parseFloat(obj.lon), parseFloat(obj.lat)],
44454               tags: obj.tags
44455             });
44456           },
44457           way: function wayData(obj, uid) {
44458             return new osmWay({
44459               id: uid,
44460               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
44461               version: obj.version && obj.version.toString(),
44462               changeset: obj.changeset && obj.changeset.toString(),
44463               timestamp: obj.timestamp,
44464               user: obj.user,
44465               uid: obj.uid && obj.uid.toString(),
44466               tags: obj.tags,
44467               nodes: getNodesJSON(obj)
44468             });
44469           },
44470           relation: function relationData(obj, uid) {
44471             return new osmRelation({
44472               id: uid,
44473               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
44474               version: obj.version && obj.version.toString(),
44475               changeset: obj.changeset && obj.changeset.toString(),
44476               timestamp: obj.timestamp,
44477               user: obj.user,
44478               uid: obj.uid && obj.uid.toString(),
44479               tags: obj.tags,
44480               members: getMembersJSON(obj)
44481             });
44482           }
44483         };
44484
44485         function parseJSON(payload, callback, options) {
44486           options = Object.assign({
44487             skipSeen: true
44488           }, options);
44489
44490           if (!payload) {
44491             return callback({
44492               message: 'No JSON',
44493               status: -1
44494             });
44495           }
44496
44497           var json = payload;
44498           if (_typeof(json) !== 'object') json = JSON.parse(payload);
44499           if (!json.elements) return callback({
44500             message: 'No JSON',
44501             status: -1
44502           });
44503           var children = json.elements;
44504           var handle = window.requestIdleCallback(function () {
44505             var results = [];
44506             var result;
44507
44508             for (var i = 0; i < children.length; i++) {
44509               result = parseChild(children[i]);
44510               if (result) results.push(result);
44511             }
44512
44513             callback(null, results);
44514           });
44515
44516           _deferred.add(handle);
44517
44518           function parseChild(child) {
44519             var parser = jsonparsers[child.type];
44520             if (!parser) return null;
44521             var uid;
44522             uid = osmEntity.id.fromOSM(child.type, child.id);
44523
44524             if (options.skipSeen) {
44525               if (_tileCache.seen[uid]) return null; // avoid reparsing a "seen" entity
44526
44527               _tileCache.seen[uid] = true;
44528             }
44529
44530             return parser(child, uid);
44531           }
44532         }
44533
44534         var parsers = {
44535           node: function nodeData(obj, uid) {
44536             var attrs = obj.attributes;
44537             return new osmNode({
44538               id: uid,
44539               visible: getVisible(attrs),
44540               version: attrs.version.value,
44541               changeset: attrs.changeset && attrs.changeset.value,
44542               timestamp: attrs.timestamp && attrs.timestamp.value,
44543               user: attrs.user && attrs.user.value,
44544               uid: attrs.uid && attrs.uid.value,
44545               loc: getLoc(attrs),
44546               tags: getTags(obj)
44547             });
44548           },
44549           way: function wayData(obj, uid) {
44550             var attrs = obj.attributes;
44551             return new osmWay({
44552               id: uid,
44553               visible: getVisible(attrs),
44554               version: attrs.version.value,
44555               changeset: attrs.changeset && attrs.changeset.value,
44556               timestamp: attrs.timestamp && attrs.timestamp.value,
44557               user: attrs.user && attrs.user.value,
44558               uid: attrs.uid && attrs.uid.value,
44559               tags: getTags(obj),
44560               nodes: getNodes(obj)
44561             });
44562           },
44563           relation: function relationData(obj, uid) {
44564             var attrs = obj.attributes;
44565             return new osmRelation({
44566               id: uid,
44567               visible: getVisible(attrs),
44568               version: attrs.version.value,
44569               changeset: attrs.changeset && attrs.changeset.value,
44570               timestamp: attrs.timestamp && attrs.timestamp.value,
44571               user: attrs.user && attrs.user.value,
44572               uid: attrs.uid && attrs.uid.value,
44573               tags: getTags(obj),
44574               members: getMembers(obj)
44575             });
44576           },
44577           note: function parseNote(obj, uid) {
44578             var attrs = obj.attributes;
44579             var childNodes = obj.childNodes;
44580             var props = {};
44581             props.id = uid;
44582             props.loc = getLoc(attrs); // if notes are coincident, move them apart slightly
44583
44584             var coincident = false;
44585             var epsilon = 0.00001;
44586
44587             do {
44588               if (coincident) {
44589                 props.loc = geoVecAdd(props.loc, [epsilon, epsilon]);
44590               }
44591
44592               var bbox = geoExtent(props.loc).bbox();
44593               coincident = _noteCache.rtree.search(bbox).length;
44594             } while (coincident); // parse note contents
44595
44596
44597             for (var i = 0; i < childNodes.length; i++) {
44598               var node = childNodes[i];
44599               var nodeName = node.nodeName;
44600               if (nodeName === '#text') continue; // if the element is comments, parse the comments
44601
44602               if (nodeName === 'comments') {
44603                 props[nodeName] = parseComments(node.childNodes);
44604               } else {
44605                 props[nodeName] = node.textContent;
44606               }
44607             }
44608
44609             var note = new osmNote(props);
44610             var item = encodeNoteRtree(note);
44611             _noteCache.note[note.id] = note;
44612
44613             _noteCache.rtree.insert(item);
44614
44615             return note;
44616           },
44617           user: function parseUser(obj, uid) {
44618             var attrs = obj.attributes;
44619             var user = {
44620               id: uid,
44621               display_name: attrs.display_name && attrs.display_name.value,
44622               account_created: attrs.account_created && attrs.account_created.value,
44623               changesets_count: '0',
44624               active_blocks: '0'
44625             };
44626             var img = obj.getElementsByTagName('img');
44627
44628             if (img && img[0] && img[0].getAttribute('href')) {
44629               user.image_url = img[0].getAttribute('href');
44630             }
44631
44632             var changesets = obj.getElementsByTagName('changesets');
44633
44634             if (changesets && changesets[0] && changesets[0].getAttribute('count')) {
44635               user.changesets_count = changesets[0].getAttribute('count');
44636             }
44637
44638             var blocks = obj.getElementsByTagName('blocks');
44639
44640             if (blocks && blocks[0]) {
44641               var received = blocks[0].getElementsByTagName('received');
44642
44643               if (received && received[0] && received[0].getAttribute('active')) {
44644                 user.active_blocks = received[0].getAttribute('active');
44645               }
44646             }
44647
44648             _userCache.user[uid] = user;
44649             delete _userCache.toLoad[uid];
44650             return user;
44651           }
44652         };
44653
44654         function parseXML(xml, callback, options) {
44655           options = Object.assign({
44656             skipSeen: true
44657           }, options);
44658
44659           if (!xml || !xml.childNodes) {
44660             return callback({
44661               message: 'No XML',
44662               status: -1
44663             });
44664           }
44665
44666           var root = xml.childNodes[0];
44667           var children = root.childNodes;
44668           var handle = window.requestIdleCallback(function () {
44669             var results = [];
44670             var result;
44671
44672             for (var i = 0; i < children.length; i++) {
44673               result = parseChild(children[i]);
44674               if (result) results.push(result);
44675             }
44676
44677             callback(null, results);
44678           });
44679
44680           _deferred.add(handle);
44681
44682           function parseChild(child) {
44683             var parser = parsers[child.nodeName];
44684             if (!parser) return null;
44685             var uid;
44686
44687             if (child.nodeName === 'user') {
44688               uid = child.attributes.id.value;
44689
44690               if (options.skipSeen && _userCache.user[uid]) {
44691                 delete _userCache.toLoad[uid];
44692                 return null;
44693               }
44694             } else if (child.nodeName === 'note') {
44695               uid = child.getElementsByTagName('id')[0].textContent;
44696             } else {
44697               uid = osmEntity.id.fromOSM(child.nodeName, child.attributes.id.value);
44698
44699               if (options.skipSeen) {
44700                 if (_tileCache.seen[uid]) return null; // avoid reparsing a "seen" entity
44701
44702                 _tileCache.seen[uid] = true;
44703               }
44704             }
44705
44706             return parser(child, uid);
44707           }
44708         } // replace or remove note from rtree
44709
44710
44711         function updateRtree$3(item, replace) {
44712           _noteCache.rtree.remove(item, function isEql(a, b) {
44713             return a.data.id === b.data.id;
44714           });
44715
44716           if (replace) {
44717             _noteCache.rtree.insert(item);
44718           }
44719         }
44720
44721         function wrapcb(thisArg, callback, cid) {
44722           return function (err, result) {
44723             if (err) {
44724               // 400 Bad Request, 401 Unauthorized, 403 Forbidden..
44725               if (err.status === 400 || err.status === 401 || err.status === 403) {
44726                 thisArg.logout();
44727               }
44728
44729               return callback.call(thisArg, err);
44730             } else if (thisArg.getConnectionId() !== cid) {
44731               return callback.call(thisArg, {
44732                 message: 'Connection Switched',
44733                 status: -1
44734               });
44735             } else {
44736               return callback.call(thisArg, err, result);
44737             }
44738           };
44739         }
44740
44741         var serviceOsm = {
44742           init: function init() {
44743             utilRebind(this, dispatch$6, 'on');
44744           },
44745           reset: function reset() {
44746             Array.from(_deferred).forEach(function (handle) {
44747               window.cancelIdleCallback(handle);
44748
44749               _deferred["delete"](handle);
44750             });
44751             _connectionID++;
44752             _userChangesets = undefined;
44753             _userDetails = undefined;
44754             _rateLimitError = undefined;
44755             Object.values(_tileCache.inflight).forEach(abortRequest$5);
44756             Object.values(_noteCache.inflight).forEach(abortRequest$5);
44757             Object.values(_noteCache.inflightPost).forEach(abortRequest$5);
44758             if (_changeset.inflight) abortRequest$5(_changeset.inflight);
44759             _tileCache = {
44760               toLoad: {},
44761               loaded: {},
44762               inflight: {},
44763               seen: {},
44764               rtree: new RBush()
44765             };
44766             _noteCache = {
44767               toLoad: {},
44768               loaded: {},
44769               inflight: {},
44770               inflightPost: {},
44771               note: {},
44772               closed: {},
44773               rtree: new RBush()
44774             };
44775             _userCache = {
44776               toLoad: {},
44777               user: {}
44778             };
44779             _cachedApiStatus = undefined;
44780             _changeset = {};
44781             return this;
44782           },
44783           getConnectionId: function getConnectionId() {
44784             return _connectionID;
44785           },
44786           changesetURL: function changesetURL(changesetID) {
44787             return urlroot + '/changeset/' + changesetID;
44788           },
44789           changesetsURL: function changesetsURL(center, zoom) {
44790             var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
44791             return urlroot + '/history#map=' + Math.floor(zoom) + '/' + center[1].toFixed(precision) + '/' + center[0].toFixed(precision);
44792           },
44793           entityURL: function entityURL(entity) {
44794             return urlroot + '/' + entity.type + '/' + entity.osmId();
44795           },
44796           historyURL: function historyURL(entity) {
44797             return urlroot + '/' + entity.type + '/' + entity.osmId() + '/history';
44798           },
44799           userURL: function userURL(username) {
44800             return urlroot + '/user/' + username;
44801           },
44802           noteURL: function noteURL(note) {
44803             return urlroot + '/note/' + note.id;
44804           },
44805           noteReportURL: function noteReportURL(note) {
44806             return urlroot + '/reports/new?reportable_type=Note&reportable_id=' + note.id;
44807           },
44808           // Generic method to load data from the OSM API
44809           // Can handle either auth or unauth calls.
44810           loadFromAPI: function loadFromAPI(path, callback, options) {
44811             options = Object.assign({
44812               skipSeen: true
44813             }, options);
44814             var that = this;
44815             var cid = _connectionID;
44816
44817             function done(err, payload) {
44818               if (that.getConnectionId() !== cid) {
44819                 if (callback) callback({
44820                   message: 'Connection Switched',
44821                   status: -1
44822                 });
44823                 return;
44824               }
44825
44826               var isAuthenticated = that.authenticated(); // 400 Bad Request, 401 Unauthorized, 403 Forbidden
44827               // Logout and retry the request..
44828
44829               if (isAuthenticated && err && err.status && (err.status === 400 || err.status === 401 || err.status === 403)) {
44830                 that.logout();
44831                 that.loadFromAPI(path, callback, options); // else, no retry..
44832               } else {
44833                 // 509 Bandwidth Limit Exceeded, 429 Too Many Requests
44834                 // Set the rateLimitError flag and trigger a warning..
44835                 if (!isAuthenticated && !_rateLimitError && err && err.status && (err.status === 509 || err.status === 429)) {
44836                   _rateLimitError = err;
44837                   dispatch$6.call('change');
44838                   that.reloadApiStatus();
44839                 } else if (err && _cachedApiStatus === 'online' || !err && _cachedApiStatus !== 'online') {
44840                   // If the response's error state doesn't match the status,
44841                   // it's likely we lost or gained the connection so reload the status
44842                   that.reloadApiStatus();
44843                 }
44844
44845                 if (callback) {
44846                   if (err) {
44847                     return callback(err);
44848                   } else {
44849                     if (path.indexOf('.json') !== -1) {
44850                       return parseJSON(payload, callback, options);
44851                     } else {
44852                       return parseXML(payload, callback, options);
44853                     }
44854                   }
44855                 }
44856               }
44857             }
44858
44859             if (this.authenticated()) {
44860               return oauth.xhr({
44861                 method: 'GET',
44862                 path: path
44863               }, done);
44864             } else {
44865               var url = urlroot + path;
44866               var controller = new AbortController();
44867               d3_json(url, {
44868                 signal: controller.signal
44869               }).then(function (data) {
44870                 done(null, data);
44871               })["catch"](function (err) {
44872                 if (err.name === 'AbortError') return; // d3-fetch includes status in the error message,
44873                 // but we can't access the response itself
44874                 // https://github.com/d3/d3-fetch/issues/27
44875
44876                 var match = err.message.match(/^\d{3}/);
44877
44878                 if (match) {
44879                   done({
44880                     status: +match[0],
44881                     statusText: err.message
44882                   });
44883                 } else {
44884                   done(err.message);
44885                 }
44886               });
44887               return controller;
44888             }
44889           },
44890           // Load a single entity by id (ways and relations use the `/full` call)
44891           // GET /api/0.6/node/#id
44892           // GET /api/0.6/[way|relation]/#id/full
44893           loadEntity: function loadEntity(id, callback) {
44894             var type = osmEntity.id.type(id);
44895             var osmID = osmEntity.id.toOSM(id);
44896             var options = {
44897               skipSeen: false
44898             };
44899             this.loadFromAPI('/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : '') + '.json', function (err, entities) {
44900               if (callback) callback(err, {
44901                 data: entities
44902               });
44903             }, options);
44904           },
44905           // Load a single entity with a specific version
44906           // GET /api/0.6/[node|way|relation]/#id/#version
44907           loadEntityVersion: function loadEntityVersion(id, version, callback) {
44908             var type = osmEntity.id.type(id);
44909             var osmID = osmEntity.id.toOSM(id);
44910             var options = {
44911               skipSeen: false
44912             };
44913             this.loadFromAPI('/api/0.6/' + type + '/' + osmID + '/' + version + '.json', function (err, entities) {
44914               if (callback) callback(err, {
44915                 data: entities
44916               });
44917             }, options);
44918           },
44919           // Load multiple entities in chunks
44920           // (note: callback may be called multiple times)
44921           // Unlike `loadEntity`, child nodes and members are not fetched
44922           // GET /api/0.6/[nodes|ways|relations]?#parameters
44923           loadMultiple: function loadMultiple(ids, callback) {
44924             var that = this;
44925             var groups = utilArrayGroupBy(utilArrayUniq(ids), osmEntity.id.type);
44926             Object.keys(groups).forEach(function (k) {
44927               var type = k + 's'; // nodes, ways, relations
44928
44929               var osmIDs = groups[k].map(function (id) {
44930                 return osmEntity.id.toOSM(id);
44931               });
44932               var options = {
44933                 skipSeen: false
44934               };
44935               utilArrayChunk(osmIDs, 150).forEach(function (arr) {
44936                 that.loadFromAPI('/api/0.6/' + type + '.json?' + type + '=' + arr.join(), function (err, entities) {
44937                   if (callback) callback(err, {
44938                     data: entities
44939                   });
44940                 }, options);
44941               });
44942             });
44943           },
44944           // Create, upload, and close a changeset
44945           // PUT /api/0.6/changeset/create
44946           // POST /api/0.6/changeset/#id/upload
44947           // PUT /api/0.6/changeset/#id/close
44948           putChangeset: function putChangeset(changeset, changes, callback) {
44949             var cid = _connectionID;
44950
44951             if (_changeset.inflight) {
44952               return callback({
44953                 message: 'Changeset already inflight',
44954                 status: -2
44955               }, changeset);
44956             } else if (_changeset.open) {
44957               // reuse existing open changeset..
44958               return createdChangeset.call(this, null, _changeset.open);
44959             } else {
44960               // Open a new changeset..
44961               var options = {
44962                 method: 'PUT',
44963                 path: '/api/0.6/changeset/create',
44964                 options: {
44965                   header: {
44966                     'Content-Type': 'text/xml'
44967                   }
44968                 },
44969                 content: JXON.stringify(changeset.asJXON())
44970               };
44971               _changeset.inflight = oauth.xhr(options, wrapcb(this, createdChangeset, cid));
44972             }
44973
44974             function createdChangeset(err, changesetID) {
44975               _changeset.inflight = null;
44976
44977               if (err) {
44978                 return callback(err, changeset);
44979               }
44980
44981               _changeset.open = changesetID;
44982               changeset = changeset.update({
44983                 id: changesetID
44984               }); // Upload the changeset..
44985
44986               var options = {
44987                 method: 'POST',
44988                 path: '/api/0.6/changeset/' + changesetID + '/upload',
44989                 options: {
44990                   header: {
44991                     'Content-Type': 'text/xml'
44992                   }
44993                 },
44994                 content: JXON.stringify(changeset.osmChangeJXON(changes))
44995               };
44996               _changeset.inflight = oauth.xhr(options, wrapcb(this, uploadedChangeset, cid));
44997             }
44998
44999             function uploadedChangeset(err) {
45000               _changeset.inflight = null;
45001               if (err) return callback(err, changeset); // Upload was successful, safe to call the callback.
45002               // Add delay to allow for postgres replication #1646 #2678
45003
45004               window.setTimeout(function () {
45005                 callback(null, changeset);
45006               }, 2500);
45007               _changeset.open = null; // At this point, we don't really care if the connection was switched..
45008               // Only try to close the changeset if we're still talking to the same server.
45009
45010               if (this.getConnectionId() === cid) {
45011                 // Still attempt to close changeset, but ignore response because #2667
45012                 oauth.xhr({
45013                   method: 'PUT',
45014                   path: '/api/0.6/changeset/' + changeset.id + '/close',
45015                   options: {
45016                     header: {
45017                       'Content-Type': 'text/xml'
45018                     }
45019                   }
45020                 }, function () {
45021                   return true;
45022                 });
45023               }
45024             }
45025           },
45026           // Load multiple users in chunks
45027           // (note: callback may be called multiple times)
45028           // GET /api/0.6/users?users=#id1,#id2,...,#idn
45029           loadUsers: function loadUsers(uids, callback) {
45030             var toLoad = [];
45031             var cached = [];
45032             utilArrayUniq(uids).forEach(function (uid) {
45033               if (_userCache.user[uid]) {
45034                 delete _userCache.toLoad[uid];
45035                 cached.push(_userCache.user[uid]);
45036               } else {
45037                 toLoad.push(uid);
45038               }
45039             });
45040
45041             if (cached.length || !this.authenticated()) {
45042               callback(undefined, cached);
45043               if (!this.authenticated()) return; // require auth
45044             }
45045
45046             utilArrayChunk(toLoad, 150).forEach(function (arr) {
45047               oauth.xhr({
45048                 method: 'GET',
45049                 path: '/api/0.6/users?users=' + arr.join()
45050               }, wrapcb(this, done, _connectionID));
45051             }.bind(this));
45052
45053             function done(err, xml) {
45054               if (err) {
45055                 return callback(err);
45056               }
45057
45058               var options = {
45059                 skipSeen: true
45060               };
45061               return parseXML(xml, function (err, results) {
45062                 if (err) {
45063                   return callback(err);
45064                 } else {
45065                   return callback(undefined, results);
45066                 }
45067               }, options);
45068             }
45069           },
45070           // Load a given user by id
45071           // GET /api/0.6/user/#id
45072           loadUser: function loadUser(uid, callback) {
45073             if (_userCache.user[uid] || !this.authenticated()) {
45074               // require auth
45075               delete _userCache.toLoad[uid];
45076               return callback(undefined, _userCache.user[uid]);
45077             }
45078
45079             oauth.xhr({
45080               method: 'GET',
45081               path: '/api/0.6/user/' + uid
45082             }, wrapcb(this, done, _connectionID));
45083
45084             function done(err, xml) {
45085               if (err) {
45086                 return callback(err);
45087               }
45088
45089               var options = {
45090                 skipSeen: true
45091               };
45092               return parseXML(xml, function (err, results) {
45093                 if (err) {
45094                   return callback(err);
45095                 } else {
45096                   return callback(undefined, results[0]);
45097                 }
45098               }, options);
45099             }
45100           },
45101           // Load the details of the logged-in user
45102           // GET /api/0.6/user/details
45103           userDetails: function userDetails(callback) {
45104             if (_userDetails) {
45105               // retrieve cached
45106               return callback(undefined, _userDetails);
45107             }
45108
45109             oauth.xhr({
45110               method: 'GET',
45111               path: '/api/0.6/user/details'
45112             }, wrapcb(this, done, _connectionID));
45113
45114             function done(err, xml) {
45115               if (err) {
45116                 return callback(err);
45117               }
45118
45119               var options = {
45120                 skipSeen: false
45121               };
45122               return parseXML(xml, function (err, results) {
45123                 if (err) {
45124                   return callback(err);
45125                 } else {
45126                   _userDetails = results[0];
45127                   return callback(undefined, _userDetails);
45128                 }
45129               }, options);
45130             }
45131           },
45132           // Load previous changesets for the logged in user
45133           // GET /api/0.6/changesets?user=#id
45134           userChangesets: function userChangesets(callback) {
45135             if (_userChangesets) {
45136               // retrieve cached
45137               return callback(undefined, _userChangesets);
45138             }
45139
45140             this.userDetails(wrapcb(this, gotDetails, _connectionID));
45141
45142             function gotDetails(err, user) {
45143               if (err) {
45144                 return callback(err);
45145               }
45146
45147               oauth.xhr({
45148                 method: 'GET',
45149                 path: '/api/0.6/changesets?user=' + user.id
45150               }, wrapcb(this, done, _connectionID));
45151             }
45152
45153             function done(err, xml) {
45154               if (err) {
45155                 return callback(err);
45156               }
45157
45158               _userChangesets = Array.prototype.map.call(xml.getElementsByTagName('changeset'), function (changeset) {
45159                 return {
45160                   tags: getTags(changeset)
45161                 };
45162               }).filter(function (changeset) {
45163                 var comment = changeset.tags.comment;
45164                 return comment && comment !== '';
45165               });
45166               return callback(undefined, _userChangesets);
45167             }
45168           },
45169           // Fetch the status of the OSM API
45170           // GET /api/capabilities
45171           status: function status(callback) {
45172             var url = urlroot + '/api/capabilities';
45173             var errback = wrapcb(this, done, _connectionID);
45174             d3_xml(url).then(function (data) {
45175               errback(null, data);
45176             })["catch"](function (err) {
45177               errback(err.message);
45178             });
45179
45180             function done(err, xml) {
45181               if (err) {
45182                 // the status is null if no response could be retrieved
45183                 return callback(err, null);
45184               } // update blocklists
45185
45186
45187               var elements = xml.getElementsByTagName('blacklist');
45188               var regexes = [];
45189
45190               for (var i = 0; i < elements.length; i++) {
45191                 var regexString = elements[i].getAttribute('regex'); // needs unencode?
45192
45193                 if (regexString) {
45194                   try {
45195                     var regex = new RegExp(regexString);
45196                     regexes.push(regex);
45197                   } catch (e) {
45198                     /* noop */
45199                   }
45200                 }
45201               }
45202
45203               if (regexes.length) {
45204                 _imageryBlocklists = regexes;
45205               }
45206
45207               if (_rateLimitError) {
45208                 return callback(_rateLimitError, 'rateLimited');
45209               } else {
45210                 var waynodes = xml.getElementsByTagName('waynodes');
45211                 var maxWayNodes = waynodes.length && parseInt(waynodes[0].getAttribute('maximum'), 10);
45212                 if (maxWayNodes && isFinite(maxWayNodes)) _maxWayNodes = maxWayNodes;
45213                 var apiStatus = xml.getElementsByTagName('status');
45214                 var val = apiStatus[0].getAttribute('api');
45215                 return callback(undefined, val);
45216               }
45217             }
45218           },
45219           // Calls `status` and dispatches an `apiStatusChange` event if the returned
45220           // status differs from the cached status.
45221           reloadApiStatus: function reloadApiStatus() {
45222             // throttle to avoid unnecessary API calls
45223             if (!this.throttledReloadApiStatus) {
45224               var that = this;
45225               this.throttledReloadApiStatus = throttle(function () {
45226                 that.status(function (err, status) {
45227                   if (status !== _cachedApiStatus) {
45228                     _cachedApiStatus = status;
45229                     dispatch$6.call('apiStatusChange', that, err, status);
45230                   }
45231                 });
45232               }, 500);
45233             }
45234
45235             this.throttledReloadApiStatus();
45236           },
45237           // Returns the maximum number of nodes a single way can have
45238           maxWayNodes: function maxWayNodes() {
45239             return _maxWayNodes;
45240           },
45241           // Load data (entities) from the API in tiles
45242           // GET /api/0.6/map?bbox=
45243           loadTiles: function loadTiles(projection, callback) {
45244             if (_off) return; // determine the needed tiles to cover the view
45245
45246             var tiles = tiler$5.zoomExtent([_tileZoom$3, _tileZoom$3]).getTiles(projection); // abort inflight requests that are no longer needed
45247
45248             var hadRequests = hasInflightRequests(_tileCache);
45249             abortUnwantedRequests$3(_tileCache, tiles);
45250
45251             if (hadRequests && !hasInflightRequests(_tileCache)) {
45252               dispatch$6.call('loaded'); // stop the spinner
45253             } // issue new requests..
45254
45255
45256             tiles.forEach(function (tile) {
45257               this.loadTile(tile, callback);
45258             }, this);
45259           },
45260           // Load a single data tile
45261           // GET /api/0.6/map?bbox=
45262           loadTile: function loadTile(tile, callback) {
45263             if (_off) return;
45264             if (_tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
45265
45266             if (!hasInflightRequests(_tileCache)) {
45267               dispatch$6.call('loading'); // start the spinner
45268             }
45269
45270             var path = '/api/0.6/map.json?bbox=';
45271             var options = {
45272               skipSeen: true
45273             };
45274             _tileCache.inflight[tile.id] = this.loadFromAPI(path + tile.extent.toParam(), tileCallback, options);
45275
45276             function tileCallback(err, parsed) {
45277               delete _tileCache.inflight[tile.id];
45278
45279               if (!err) {
45280                 delete _tileCache.toLoad[tile.id];
45281                 _tileCache.loaded[tile.id] = true;
45282                 var bbox = tile.extent.bbox();
45283                 bbox.id = tile.id;
45284
45285                 _tileCache.rtree.insert(bbox);
45286               }
45287
45288               if (callback) {
45289                 callback(err, Object.assign({
45290                   data: parsed
45291                 }, tile));
45292               }
45293
45294               if (!hasInflightRequests(_tileCache)) {
45295                 dispatch$6.call('loaded'); // stop the spinner
45296               }
45297             }
45298           },
45299           isDataLoaded: function isDataLoaded(loc) {
45300             var bbox = {
45301               minX: loc[0],
45302               minY: loc[1],
45303               maxX: loc[0],
45304               maxY: loc[1]
45305             };
45306             return _tileCache.rtree.collides(bbox);
45307           },
45308           // load the tile that covers the given `loc`
45309           loadTileAtLoc: function loadTileAtLoc(loc, callback) {
45310             // Back off if the toLoad queue is filling up.. re #6417
45311             // (Currently `loadTileAtLoc` requests are considered low priority - used by operations to
45312             // let users safely edit geometries which extend to unloaded tiles.  We can drop some.)
45313             if (Object.keys(_tileCache.toLoad).length > 50) return;
45314             var k = geoZoomToScale(_tileZoom$3 + 1);
45315             var offset = geoRawMercator().scale(k)(loc);
45316             var projection = geoRawMercator().transform({
45317               k: k,
45318               x: -offset[0],
45319               y: -offset[1]
45320             });
45321             var tiles = tiler$5.zoomExtent([_tileZoom$3, _tileZoom$3]).getTiles(projection);
45322             tiles.forEach(function (tile) {
45323               if (_tileCache.toLoad[tile.id] || _tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
45324               _tileCache.toLoad[tile.id] = true;
45325               this.loadTile(tile, callback);
45326             }, this);
45327           },
45328           // Load notes from the API in tiles
45329           // GET /api/0.6/notes?bbox=
45330           loadNotes: function loadNotes(projection, noteOptions) {
45331             noteOptions = Object.assign({
45332               limit: 10000,
45333               closed: 7
45334             }, noteOptions);
45335             if (_off) return;
45336             var that = this;
45337             var path = '/api/0.6/notes?limit=' + noteOptions.limit + '&closed=' + noteOptions.closed + '&bbox=';
45338
45339             var throttleLoadUsers = throttle(function () {
45340               var uids = Object.keys(_userCache.toLoad);
45341               if (!uids.length) return;
45342               that.loadUsers(uids, function () {}); // eagerly load user details
45343             }, 750); // determine the needed tiles to cover the view
45344
45345
45346             var tiles = tiler$5.zoomExtent([_noteZoom, _noteZoom]).getTiles(projection); // abort inflight requests that are no longer needed
45347
45348             abortUnwantedRequests$3(_noteCache, tiles); // issue new requests..
45349
45350             tiles.forEach(function (tile) {
45351               if (_noteCache.loaded[tile.id] || _noteCache.inflight[tile.id]) return;
45352               var options = {
45353                 skipSeen: false
45354               };
45355               _noteCache.inflight[tile.id] = that.loadFromAPI(path + tile.extent.toParam(), function (err) {
45356                 delete _noteCache.inflight[tile.id];
45357
45358                 if (!err) {
45359                   _noteCache.loaded[tile.id] = true;
45360                 }
45361
45362                 throttleLoadUsers();
45363                 dispatch$6.call('loadedNotes');
45364               }, options);
45365             });
45366           },
45367           // Create a note
45368           // POST /api/0.6/notes?params
45369           postNoteCreate: function postNoteCreate(note, callback) {
45370             if (!this.authenticated()) {
45371               return callback({
45372                 message: 'Not Authenticated',
45373                 status: -3
45374               }, note);
45375             }
45376
45377             if (_noteCache.inflightPost[note.id]) {
45378               return callback({
45379                 message: 'Note update already inflight',
45380                 status: -2
45381               }, note);
45382             }
45383
45384             if (!note.loc[0] || !note.loc[1] || !note.newComment) return; // location & description required
45385
45386             var comment = note.newComment;
45387
45388             if (note.newCategory && note.newCategory !== 'None') {
45389               comment += ' #' + note.newCategory;
45390             }
45391
45392             var path = '/api/0.6/notes?' + utilQsString({
45393               lon: note.loc[0],
45394               lat: note.loc[1],
45395               text: comment
45396             });
45397             _noteCache.inflightPost[note.id] = oauth.xhr({
45398               method: 'POST',
45399               path: path
45400             }, wrapcb(this, done, _connectionID));
45401
45402             function done(err, xml) {
45403               delete _noteCache.inflightPost[note.id];
45404
45405               if (err) {
45406                 return callback(err);
45407               } // we get the updated note back, remove from caches and reparse..
45408
45409
45410               this.removeNote(note);
45411               var options = {
45412                 skipSeen: false
45413               };
45414               return parseXML(xml, function (err, results) {
45415                 if (err) {
45416                   return callback(err);
45417                 } else {
45418                   return callback(undefined, results[0]);
45419                 }
45420               }, options);
45421             }
45422           },
45423           // Update a note
45424           // POST /api/0.6/notes/#id/comment?text=comment
45425           // POST /api/0.6/notes/#id/close?text=comment
45426           // POST /api/0.6/notes/#id/reopen?text=comment
45427           postNoteUpdate: function postNoteUpdate(note, newStatus, callback) {
45428             if (!this.authenticated()) {
45429               return callback({
45430                 message: 'Not Authenticated',
45431                 status: -3
45432               }, note);
45433             }
45434
45435             if (_noteCache.inflightPost[note.id]) {
45436               return callback({
45437                 message: 'Note update already inflight',
45438                 status: -2
45439               }, note);
45440             }
45441
45442             var action;
45443
45444             if (note.status !== 'closed' && newStatus === 'closed') {
45445               action = 'close';
45446             } else if (note.status !== 'open' && newStatus === 'open') {
45447               action = 'reopen';
45448             } else {
45449               action = 'comment';
45450               if (!note.newComment) return; // when commenting, comment required
45451             }
45452
45453             var path = '/api/0.6/notes/' + note.id + '/' + action;
45454
45455             if (note.newComment) {
45456               path += '?' + utilQsString({
45457                 text: note.newComment
45458               });
45459             }
45460
45461             _noteCache.inflightPost[note.id] = oauth.xhr({
45462               method: 'POST',
45463               path: path
45464             }, wrapcb(this, done, _connectionID));
45465
45466             function done(err, xml) {
45467               delete _noteCache.inflightPost[note.id];
45468
45469               if (err) {
45470                 return callback(err);
45471               } // we get the updated note back, remove from caches and reparse..
45472
45473
45474               this.removeNote(note); // update closed note cache - used to populate `closed:note` changeset tag
45475
45476               if (action === 'close') {
45477                 _noteCache.closed[note.id] = true;
45478               } else if (action === 'reopen') {
45479                 delete _noteCache.closed[note.id];
45480               }
45481
45482               var options = {
45483                 skipSeen: false
45484               };
45485               return parseXML(xml, function (err, results) {
45486                 if (err) {
45487                   return callback(err);
45488                 } else {
45489                   return callback(undefined, results[0]);
45490                 }
45491               }, options);
45492             }
45493           },
45494           "switch": function _switch(options) {
45495             urlroot = options.urlroot;
45496             oauth.options(Object.assign({
45497               url: urlroot,
45498               loading: authLoading,
45499               done: authDone
45500             }, options));
45501             this.reset();
45502             this.userChangesets(function () {}); // eagerly load user details/changesets
45503
45504             dispatch$6.call('change');
45505             return this;
45506           },
45507           toggle: function toggle(val) {
45508             _off = !val;
45509             return this;
45510           },
45511           isChangesetInflight: function isChangesetInflight() {
45512             return !!_changeset.inflight;
45513           },
45514           // get/set cached data
45515           // This is used to save/restore the state when entering/exiting the walkthrough
45516           // Also used for testing purposes.
45517           caches: function caches(obj) {
45518             function cloneCache(source) {
45519               var target = {};
45520               Object.keys(source).forEach(function (k) {
45521                 if (k === 'rtree') {
45522                   target.rtree = new RBush().fromJSON(source.rtree.toJSON()); // clone rbush
45523                 } else if (k === 'note') {
45524                   target.note = {};
45525                   Object.keys(source.note).forEach(function (id) {
45526                     target.note[id] = osmNote(source.note[id]); // copy notes
45527                   });
45528                 } else {
45529                   target[k] = JSON.parse(JSON.stringify(source[k])); // clone deep
45530                 }
45531               });
45532               return target;
45533             }
45534
45535             if (!arguments.length) {
45536               return {
45537                 tile: cloneCache(_tileCache),
45538                 note: cloneCache(_noteCache),
45539                 user: cloneCache(_userCache)
45540               };
45541             } // access caches directly for testing (e.g., loading notes rtree)
45542
45543
45544             if (obj === 'get') {
45545               return {
45546                 tile: _tileCache,
45547                 note: _noteCache,
45548                 user: _userCache
45549               };
45550             }
45551
45552             if (obj.tile) {
45553               _tileCache = obj.tile;
45554               _tileCache.inflight = {};
45555             }
45556
45557             if (obj.note) {
45558               _noteCache = obj.note;
45559               _noteCache.inflight = {};
45560               _noteCache.inflightPost = {};
45561             }
45562
45563             if (obj.user) {
45564               _userCache = obj.user;
45565             }
45566
45567             return this;
45568           },
45569           logout: function logout() {
45570             _userChangesets = undefined;
45571             _userDetails = undefined;
45572             oauth.logout();
45573             dispatch$6.call('change');
45574             return this;
45575           },
45576           authenticated: function authenticated() {
45577             return oauth.authenticated();
45578           },
45579           authenticate: function authenticate(callback) {
45580             var that = this;
45581             var cid = _connectionID;
45582             _userChangesets = undefined;
45583             _userDetails = undefined;
45584
45585             function done(err, res) {
45586               if (err) {
45587                 if (callback) callback(err);
45588                 return;
45589               }
45590
45591               if (that.getConnectionId() !== cid) {
45592                 if (callback) callback({
45593                   message: 'Connection Switched',
45594                   status: -1
45595                 });
45596                 return;
45597               }
45598
45599               _rateLimitError = undefined;
45600               dispatch$6.call('change');
45601               if (callback) callback(err, res);
45602               that.userChangesets(function () {}); // eagerly load user details/changesets
45603             }
45604
45605             return oauth.authenticate(done);
45606           },
45607           imageryBlocklists: function imageryBlocklists() {
45608             return _imageryBlocklists;
45609           },
45610           tileZoom: function tileZoom(val) {
45611             if (!arguments.length) return _tileZoom$3;
45612             _tileZoom$3 = val;
45613             return this;
45614           },
45615           // get all cached notes covering the viewport
45616           notes: function notes(projection) {
45617             var viewport = projection.clipExtent();
45618             var min = [viewport[0][0], viewport[1][1]];
45619             var max = [viewport[1][0], viewport[0][1]];
45620             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
45621             return _noteCache.rtree.search(bbox).map(function (d) {
45622               return d.data;
45623             });
45624           },
45625           // get a single note from the cache
45626           getNote: function getNote(id) {
45627             return _noteCache.note[id];
45628           },
45629           // remove a single note from the cache
45630           removeNote: function removeNote(note) {
45631             if (!(note instanceof osmNote) || !note.id) return;
45632             delete _noteCache.note[note.id];
45633             updateRtree$3(encodeNoteRtree(note), false); // false = remove
45634           },
45635           // replace a single note in the cache
45636           replaceNote: function replaceNote(note) {
45637             if (!(note instanceof osmNote) || !note.id) return;
45638             _noteCache.note[note.id] = note;
45639             updateRtree$3(encodeNoteRtree(note), true); // true = replace
45640
45641             return note;
45642           },
45643           // Get an array of note IDs closed during this session.
45644           // Used to populate `closed:note` changeset tag
45645           getClosedIDs: function getClosedIDs() {
45646             return Object.keys(_noteCache.closed).sort();
45647           }
45648         };
45649
45650         var _apibase = 'https://wiki.openstreetmap.org/w/api.php';
45651         var _inflight$1 = {};
45652         var _wikibaseCache = {};
45653         var _localeIDs = {
45654           en: false
45655         };
45656
45657         var debouncedRequest = debounce(request, 500, {
45658           leading: false
45659         });
45660
45661         function request(url, callback) {
45662           if (_inflight$1[url]) return;
45663           var controller = new AbortController();
45664           _inflight$1[url] = controller;
45665           d3_json(url, {
45666             signal: controller.signal
45667           }).then(function (result) {
45668             delete _inflight$1[url];
45669             if (callback) callback(null, result);
45670           })["catch"](function (err) {
45671             delete _inflight$1[url];
45672             if (err.name === 'AbortError') return;
45673             if (callback) callback(err.message);
45674           });
45675         }
45676
45677         var serviceOsmWikibase = {
45678           init: function init() {
45679             _inflight$1 = {};
45680             _wikibaseCache = {};
45681             _localeIDs = {};
45682           },
45683           reset: function reset() {
45684             Object.values(_inflight$1).forEach(function (controller) {
45685               controller.abort();
45686             });
45687             _inflight$1 = {};
45688           },
45689
45690           /**
45691            * Get the best value for the property, or undefined if not found
45692            * @param entity object from wikibase
45693            * @param property string e.g. 'P4' for image
45694            * @param langCode string e.g. 'fr' for French
45695            */
45696           claimToValue: function claimToValue(entity, property, langCode) {
45697             if (!entity.claims[property]) return undefined;
45698             var locale = _localeIDs[langCode];
45699             var preferredPick, localePick;
45700             entity.claims[property].forEach(function (stmt) {
45701               // If exists, use value limited to the needed language (has a qualifier P26 = locale)
45702               // Or if not found, use the first value with the "preferred" rank
45703               if (!preferredPick && stmt.rank === 'preferred') {
45704                 preferredPick = stmt;
45705               }
45706
45707               if (locale && stmt.qualifiers && stmt.qualifiers.P26 && stmt.qualifiers.P26[0].datavalue.value.id === locale) {
45708                 localePick = stmt;
45709               }
45710             });
45711             var result = localePick || preferredPick;
45712
45713             if (result) {
45714               var datavalue = result.mainsnak.datavalue;
45715               return datavalue.type === 'wikibase-entityid' ? datavalue.value.id : datavalue.value;
45716             } else {
45717               return undefined;
45718             }
45719           },
45720
45721           /**
45722            * Convert monolingual property into a key-value object (language -> value)
45723            * @param entity object from wikibase
45724            * @param property string e.g. 'P31' for monolingual wiki page title
45725            */
45726           monolingualClaimToValueObj: function monolingualClaimToValueObj(entity, property) {
45727             if (!entity || !entity.claims[property]) return undefined;
45728             return entity.claims[property].reduce(function (acc, obj) {
45729               var value = obj.mainsnak.datavalue.value;
45730               acc[value.language] = value.text;
45731               return acc;
45732             }, {});
45733           },
45734           toSitelink: function toSitelink(key, value) {
45735             var result = value ? 'Tag:' + key + '=' + value : 'Key:' + key;
45736             return result.replace(/_/g, ' ').trim();
45737           },
45738           //
45739           // Pass params object of the form:
45740           // {
45741           //   key: 'string',
45742           //   value: 'string',
45743           //   langCode: 'string'
45744           // }
45745           //
45746           getEntity: function getEntity(params, callback) {
45747             var doRequest = params.debounce ? debouncedRequest : request;
45748             var that = this;
45749             var titles = [];
45750             var result = {};
45751             var rtypeSitelink = params.key === 'type' && params.value ? ('Relation:' + params.value).replace(/_/g, ' ').trim() : false;
45752             var keySitelink = params.key ? this.toSitelink(params.key) : false;
45753             var tagSitelink = params.key && params.value ? this.toSitelink(params.key, params.value) : false;
45754             var localeSitelink;
45755
45756             if (params.langCodes) {
45757               params.langCodes.forEach(function (langCode) {
45758                 if (_localeIDs[langCode] === undefined) {
45759                   // If this is the first time we are asking about this locale,
45760                   // fetch corresponding entity (if it exists), and cache it.
45761                   // If there is no such entry, cache `false` value to avoid re-requesting it.
45762                   localeSitelink = ('Locale:' + langCode).replace(/_/g, ' ').trim();
45763                   titles.push(localeSitelink);
45764                 }
45765               });
45766             }
45767
45768             if (rtypeSitelink) {
45769               if (_wikibaseCache[rtypeSitelink]) {
45770                 result.rtype = _wikibaseCache[rtypeSitelink];
45771               } else {
45772                 titles.push(rtypeSitelink);
45773               }
45774             }
45775
45776             if (keySitelink) {
45777               if (_wikibaseCache[keySitelink]) {
45778                 result.key = _wikibaseCache[keySitelink];
45779               } else {
45780                 titles.push(keySitelink);
45781               }
45782             }
45783
45784             if (tagSitelink) {
45785               if (_wikibaseCache[tagSitelink]) {
45786                 result.tag = _wikibaseCache[tagSitelink];
45787               } else {
45788                 titles.push(tagSitelink);
45789               }
45790             }
45791
45792             if (!titles.length) {
45793               // Nothing to do, we already had everything in the cache
45794               return callback(null, result);
45795             } // Requesting just the user language code
45796             // If backend recognizes the code, it will perform proper fallbacks,
45797             // and the result will contain the requested code. If not, all values are returned:
45798             // {"zh-tw":{"value":"...","language":"zh-tw","source-language":"zh-hant"}
45799             // {"pt-br":{"value":"...","language":"pt","for-language":"pt-br"}}
45800
45801
45802             var obj = {
45803               action: 'wbgetentities',
45804               sites: 'wiki',
45805               titles: titles.join('|'),
45806               languages: params.langCodes.join('|'),
45807               languagefallback: 1,
45808               origin: '*',
45809               format: 'json' // There is an MW Wikibase API bug https://phabricator.wikimedia.org/T212069
45810               // We shouldn't use v1 until it gets fixed, but should switch to it afterwards
45811               // formatversion: 2,
45812
45813             };
45814             var url = _apibase + '?' + utilQsString(obj);
45815             doRequest(url, function (err, d) {
45816               if (err) {
45817                 callback(err);
45818               } else if (!d.success || d.error) {
45819                 callback(d.error.messages.map(function (v) {
45820                   return v.html['*'];
45821                 }).join('<br>'));
45822               } else {
45823                 var localeID = false;
45824                 Object.values(d.entities).forEach(function (res) {
45825                   if (res.missing !== '') {
45826                     var title = res.sitelinks.wiki.title;
45827
45828                     if (title === rtypeSitelink) {
45829                       _wikibaseCache[rtypeSitelink] = res;
45830                       result.rtype = res;
45831                     } else if (title === keySitelink) {
45832                       _wikibaseCache[keySitelink] = res;
45833                       result.key = res;
45834                     } else if (title === tagSitelink) {
45835                       _wikibaseCache[tagSitelink] = res;
45836                       result.tag = res;
45837                     } else if (title === localeSitelink) {
45838                       localeID = res.id;
45839                     } else {
45840                       console.log('Unexpected title ' + title); // eslint-disable-line no-console
45841                     }
45842                   }
45843                 });
45844
45845                 if (localeSitelink) {
45846                   // If locale ID is not found, store false to prevent repeated queries
45847                   that.addLocale(params.langCodes[0], localeID);
45848                 }
45849
45850                 callback(null, result);
45851               }
45852             });
45853           },
45854           //
45855           // Pass params object of the form:
45856           // {
45857           //   key: 'string',     // required
45858           //   value: 'string'    // optional
45859           // }
45860           //
45861           // Get an result object used to display tag documentation
45862           // {
45863           //   title:        'string',
45864           //   description:  'string',
45865           //   editURL:      'string',
45866           //   imageURL:     'string',
45867           //   wiki:         { title: 'string', text: 'string', url: 'string' }
45868           // }
45869           //
45870           getDocs: function getDocs(params, callback) {
45871             var that = this;
45872             var langCodes = _mainLocalizer.localeCodes().map(function (code) {
45873               return code.toLowerCase();
45874             });
45875             params.langCodes = langCodes;
45876             this.getEntity(params, function (err, data) {
45877               if (err) {
45878                 callback(err);
45879                 return;
45880               }
45881
45882               var entity = data.rtype || data.tag || data.key;
45883
45884               if (!entity) {
45885                 callback('No entity');
45886                 return;
45887               }
45888
45889               var i;
45890               var description;
45891
45892               for (i in langCodes) {
45893                 var _code = langCodes[i];
45894
45895                 if (entity.descriptions[_code] && entity.descriptions[_code].language === _code) {
45896                   description = entity.descriptions[_code];
45897                   break;
45898                 }
45899               }
45900
45901               if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result
45902
45903               var result = {
45904                 title: entity.title,
45905                 description: description ? description.value : '',
45906                 descriptionLocaleCode: description ? description.language : '',
45907                 editURL: 'https://wiki.openstreetmap.org/wiki/' + entity.title
45908               }; // add image
45909
45910               if (entity.claims) {
45911                 var imageroot;
45912                 var image = that.claimToValue(entity, 'P4', langCodes[0]);
45913
45914                 if (image) {
45915                   imageroot = 'https://commons.wikimedia.org/w/index.php';
45916                 } else {
45917                   image = that.claimToValue(entity, 'P28', langCodes[0]);
45918
45919                   if (image) {
45920                     imageroot = 'https://wiki.openstreetmap.org/w/index.php';
45921                   }
45922                 }
45923
45924                 if (imageroot && image) {
45925                   result.imageURL = imageroot + '?' + utilQsString({
45926                     title: 'Special:Redirect/file/' + image,
45927                     width: 400
45928                   });
45929                 }
45930               } // Try to get a wiki page from tag data item first, followed by the corresponding key data item.
45931               // If neither tag nor key data item contain a wiki page in the needed language nor English,
45932               // get the first found wiki page from either the tag or the key item.
45933
45934
45935               var rtypeWiki = that.monolingualClaimToValueObj(data.rtype, 'P31');
45936               var tagWiki = that.monolingualClaimToValueObj(data.tag, 'P31');
45937               var keyWiki = that.monolingualClaimToValueObj(data.key, 'P31');
45938               var wikis = [rtypeWiki, tagWiki, keyWiki];
45939
45940               for (i in wikis) {
45941                 var wiki = wikis[i];
45942
45943                 for (var j in langCodes) {
45944                   var code = langCodes[j];
45945                   var referenceId = langCodes[0].split('-')[0] !== 'en' && code.split('-')[0] === 'en' ? 'inspector.wiki_en_reference' : 'inspector.wiki_reference';
45946                   var info = getWikiInfo(wiki, code, referenceId);
45947
45948                   if (info) {
45949                     result.wiki = info;
45950                     break;
45951                   }
45952                 }
45953
45954                 if (result.wiki) break;
45955               }
45956
45957               callback(null, result); // Helper method to get wiki info if a given language exists
45958
45959               function getWikiInfo(wiki, langCode, tKey) {
45960                 if (wiki && wiki[langCode]) {
45961                   return {
45962                     title: wiki[langCode],
45963                     text: tKey,
45964                     url: 'https://wiki.openstreetmap.org/wiki/' + wiki[langCode]
45965                   };
45966                 }
45967               }
45968             });
45969           },
45970           addLocale: function addLocale(langCode, qid) {
45971             // Makes it easier to unit test
45972             _localeIDs[langCode] = qid;
45973           },
45974           apibase: function apibase(val) {
45975             if (!arguments.length) return _apibase;
45976             _apibase = val;
45977             return this;
45978           }
45979         };
45980
45981         var jsonpCache = {};
45982         window.jsonpCache = jsonpCache;
45983         function jsonpRequest(url, callback) {
45984           var request = {
45985             abort: function abort() {}
45986           };
45987
45988           if (window.JSONP_FIX) {
45989             if (window.JSONP_DELAY === 0) {
45990               callback(window.JSONP_FIX);
45991             } else {
45992               var t = window.setTimeout(function () {
45993                 callback(window.JSONP_FIX);
45994               }, window.JSONP_DELAY || 0);
45995
45996               request.abort = function () {
45997                 window.clearTimeout(t);
45998               };
45999             }
46000
46001             return request;
46002           }
46003
46004           function rand() {
46005             var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
46006             var c = '';
46007             var i = -1;
46008
46009             while (++i < 15) {
46010               c += chars.charAt(Math.floor(Math.random() * 52));
46011             }
46012
46013             return c;
46014           }
46015
46016           function create(url) {
46017             var e = url.match(/callback=(\w+)/);
46018             var c = e ? e[1] : rand();
46019
46020             jsonpCache[c] = function (data) {
46021               if (jsonpCache[c]) {
46022                 callback(data);
46023               }
46024
46025               finalize();
46026             };
46027
46028             function finalize() {
46029               delete jsonpCache[c];
46030               script.remove();
46031             }
46032
46033             request.abort = finalize;
46034             return 'jsonpCache.' + c;
46035           }
46036
46037           var cb = create(url);
46038           var script = select('head').append('script').attr('type', 'text/javascript').attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
46039           return request;
46040         }
46041
46042         var bubbleApi = 'https://dev.virtualearth.net/mapcontrol/HumanScaleServices/GetBubbles.ashx?';
46043         var streetsideImagesApi = 'https://t.ssl.ak.tiles.virtualearth.net/tiles/';
46044         var bubbleAppKey = 'AuftgJsO0Xs8Ts4M1xZUQJQXJNsvmh3IV8DkNieCiy3tCwCUMq76-WpkrBtNAuEm';
46045         var pannellumViewerCSS = 'pannellum-streetside/pannellum.css';
46046         var pannellumViewerJS = 'pannellum-streetside/pannellum.js';
46047         var maxResults$2 = 2000;
46048         var tileZoom$2 = 16.5;
46049         var tiler$6 = utilTiler().zoomExtent([tileZoom$2, tileZoom$2]).skipNullIsland(true);
46050         var dispatch$7 = dispatch('loadedImages', 'viewerChanged');
46051         var minHfov = 10; // zoom in degrees:  20, 10, 5
46052
46053         var maxHfov = 90; // zoom out degrees
46054
46055         var defaultHfov = 45;
46056         var _hires = false;
46057         var _resolution = 512; // higher numbers are slower - 512, 1024, 2048, 4096
46058
46059         var _currScene = 0;
46060
46061         var _ssCache;
46062
46063         var _pannellumViewer;
46064
46065         var _sceneOptions = {
46066           showFullscreenCtrl: false,
46067           autoLoad: true,
46068           compass: true,
46069           yaw: 0,
46070           minHfov: minHfov,
46071           maxHfov: maxHfov,
46072           hfov: defaultHfov,
46073           type: 'cubemap',
46074           cubeMap: []
46075         };
46076
46077         var _loadViewerPromise$2;
46078         /**
46079          * abortRequest().
46080          */
46081
46082
46083         function abortRequest$6(i) {
46084           i.abort();
46085         }
46086         /**
46087          * localeTimeStamp().
46088          */
46089
46090
46091         function localeTimestamp(s) {
46092           if (!s) return null;
46093           var options = {
46094             day: 'numeric',
46095             month: 'short',
46096             year: 'numeric'
46097           };
46098           var d = new Date(s);
46099           if (isNaN(d.getTime())) return null;
46100           return d.toLocaleString(_mainLocalizer.localeCode(), options);
46101         }
46102         /**
46103          * loadTiles() wraps the process of generating tiles and then fetching image points for each tile.
46104          */
46105
46106
46107         function loadTiles$2(which, url, projection, margin) {
46108           var tiles = tiler$6.margin(margin).getTiles(projection); // abort inflight requests that are no longer needed
46109
46110           var cache = _ssCache[which];
46111           Object.keys(cache.inflight).forEach(function (k) {
46112             var wanted = tiles.find(function (tile) {
46113               return k.indexOf(tile.id + ',') === 0;
46114             });
46115
46116             if (!wanted) {
46117               abortRequest$6(cache.inflight[k]);
46118               delete cache.inflight[k];
46119             }
46120           });
46121           tiles.forEach(function (tile) {
46122             return loadNextTilePage$2(which, url, tile);
46123           });
46124         }
46125         /**
46126          * loadNextTilePage() load data for the next tile page in line.
46127          */
46128
46129
46130         function loadNextTilePage$2(which, url, tile) {
46131           var cache = _ssCache[which];
46132           var nextPage = cache.nextPage[tile.id] || 0;
46133           var id = tile.id + ',' + String(nextPage);
46134           if (cache.loaded[id] || cache.inflight[id]) return;
46135           cache.inflight[id] = getBubbles(url, tile, function (bubbles) {
46136             cache.loaded[id] = true;
46137             delete cache.inflight[id];
46138             if (!bubbles) return; // [].shift() removes the first element, some statistics info, not a bubble point
46139
46140             bubbles.shift();
46141             var features = bubbles.map(function (bubble) {
46142               if (cache.points[bubble.id]) return null; // skip duplicates
46143
46144               var loc = [bubble.lo, bubble.la];
46145               var d = {
46146                 loc: loc,
46147                 key: bubble.id,
46148                 ca: bubble.he,
46149                 captured_at: bubble.cd,
46150                 captured_by: 'microsoft',
46151                 // nbn: bubble.nbn,
46152                 // pbn: bubble.pbn,
46153                 // ad: bubble.ad,
46154                 // rn: bubble.rn,
46155                 pr: bubble.pr,
46156                 // previous
46157                 ne: bubble.ne,
46158                 // next
46159                 pano: true,
46160                 sequenceKey: null
46161               };
46162               cache.points[bubble.id] = d; // a sequence starts here
46163
46164               if (bubble.pr === undefined) {
46165                 cache.leaders.push(bubble.id);
46166               }
46167
46168               return {
46169                 minX: loc[0],
46170                 minY: loc[1],
46171                 maxX: loc[0],
46172                 maxY: loc[1],
46173                 data: d
46174               };
46175             }).filter(Boolean);
46176             cache.rtree.load(features);
46177             connectSequences();
46178
46179             if (which === 'bubbles') {
46180               dispatch$7.call('loadedImages');
46181             }
46182           });
46183         } // call this sometimes to connect the bubbles into sequences
46184
46185
46186         function connectSequences() {
46187           var cache = _ssCache.bubbles;
46188           var keepLeaders = [];
46189
46190           for (var i = 0; i < cache.leaders.length; i++) {
46191             var bubble = cache.points[cache.leaders[i]];
46192             var seen = {}; // try to make a sequence.. use the key of the leader bubble.
46193
46194             var sequence = {
46195               key: bubble.key,
46196               bubbles: []
46197             };
46198             var complete = false;
46199
46200             do {
46201               sequence.bubbles.push(bubble);
46202               seen[bubble.key] = true;
46203
46204               if (bubble.ne === undefined) {
46205                 complete = true;
46206               } else {
46207                 bubble = cache.points[bubble.ne]; // advance to next
46208               }
46209             } while (bubble && !seen[bubble.key] && !complete);
46210
46211             if (complete) {
46212               _ssCache.sequences[sequence.key] = sequence; // assign bubbles to the sequence
46213
46214               for (var j = 0; j < sequence.bubbles.length; j++) {
46215                 sequence.bubbles[j].sequenceKey = sequence.key;
46216               } // create a GeoJSON LineString
46217
46218
46219               sequence.geojson = {
46220                 type: 'LineString',
46221                 properties: {
46222                   captured_at: sequence.bubbles[0] ? sequence.bubbles[0].captured_at : null,
46223                   captured_by: sequence.bubbles[0] ? sequence.bubbles[0].captured_by : null,
46224                   key: sequence.key
46225                 },
46226                 coordinates: sequence.bubbles.map(function (d) {
46227                   return d.loc;
46228                 })
46229               };
46230             } else {
46231               keepLeaders.push(cache.leaders[i]);
46232             }
46233           } // couldn't complete these, save for later
46234
46235
46236           cache.leaders = keepLeaders;
46237         }
46238         /**
46239          * getBubbles() handles the request to the server for a tile extent of 'bubbles' (streetside image locations).
46240          */
46241
46242
46243         function getBubbles(url, tile, callback) {
46244           var rect = tile.extent.rectangle();
46245           var urlForRequest = url + utilQsString({
46246             n: rect[3],
46247             s: rect[1],
46248             e: rect[2],
46249             w: rect[0],
46250             c: maxResults$2,
46251             appkey: bubbleAppKey,
46252             jsCallback: '{callback}'
46253           });
46254           return jsonpRequest(urlForRequest, function (data) {
46255             if (!data || data.error) {
46256               callback(null);
46257             } else {
46258               callback(data);
46259             }
46260           });
46261         } // partition viewport into higher zoom tiles
46262
46263
46264         function partitionViewport$2(projection) {
46265           var z = geoScaleToZoom(projection.scale());
46266           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
46267
46268           var tiler = utilTiler().zoomExtent([z2, z2]);
46269           return tiler.getTiles(projection).map(function (tile) {
46270             return tile.extent;
46271           });
46272         } // no more than `limit` results per partition.
46273
46274
46275         function searchLimited$2(limit, projection, rtree) {
46276           limit = limit || 5;
46277           return partitionViewport$2(projection).reduce(function (result, extent) {
46278             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
46279               return d.data;
46280             });
46281             return found.length ? result.concat(found) : result;
46282           }, []);
46283         }
46284         /**
46285          * loadImage()
46286          */
46287
46288
46289         function loadImage(imgInfo) {
46290           return new Promise(function (resolve) {
46291             var img = new Image();
46292
46293             img.onload = function () {
46294               var canvas = document.getElementById('ideditor-canvas' + imgInfo.face);
46295               var ctx = canvas.getContext('2d');
46296               ctx.drawImage(img, imgInfo.x, imgInfo.y);
46297               resolve({
46298                 imgInfo: imgInfo,
46299                 status: 'ok'
46300               });
46301             };
46302
46303             img.onerror = function () {
46304               resolve({
46305                 data: imgInfo,
46306                 status: 'error'
46307               });
46308             };
46309
46310             img.setAttribute('crossorigin', '');
46311             img.src = imgInfo.url;
46312           });
46313         }
46314         /**
46315          * loadCanvas()
46316          */
46317
46318
46319         function loadCanvas(imageGroup) {
46320           return Promise.all(imageGroup.map(loadImage)).then(function (data) {
46321             var canvas = document.getElementById('ideditor-canvas' + data[0].imgInfo.face);
46322             var which = {
46323               '01': 0,
46324               '02': 1,
46325               '03': 2,
46326               '10': 3,
46327               '11': 4,
46328               '12': 5
46329             };
46330             var face = data[0].imgInfo.face;
46331             _sceneOptions.cubeMap[which[face]] = canvas.toDataURL('image/jpeg', 1.0);
46332             return {
46333               status: 'loadCanvas for face ' + data[0].imgInfo.face + 'ok'
46334             };
46335           });
46336         }
46337         /**
46338          * loadFaces()
46339          */
46340
46341
46342         function loadFaces(faceGroup) {
46343           return Promise.all(faceGroup.map(loadCanvas)).then(function () {
46344             return {
46345               status: 'loadFaces done'
46346             };
46347           });
46348         }
46349
46350         function setupCanvas(selection, reset) {
46351           if (reset) {
46352             selection.selectAll('#ideditor-stitcher-canvases').remove();
46353           } // Add the Streetside working canvases. These are used for 'stitching', or combining,
46354           // multiple images for each of the six faces, before passing to the Pannellum control as DataUrls
46355
46356
46357           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) {
46358             return 'ideditor-' + d;
46359           }).attr('width', _resolution).attr('height', _resolution);
46360         }
46361
46362         function qkToXY(qk) {
46363           var x = 0;
46364           var y = 0;
46365           var scale = 256;
46366
46367           for (var i = qk.length; i > 0; i--) {
46368             var key = qk[i - 1];
46369             x += +(key === '1' || key === '3') * scale;
46370             y += +(key === '2' || key === '3') * scale;
46371             scale *= 2;
46372           }
46373
46374           return [x, y];
46375         }
46376
46377         function getQuadKeys() {
46378           var dim = _resolution / 256;
46379           var quadKeys;
46380
46381           if (dim === 16) {
46382             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'];
46383           } else if (dim === 8) {
46384             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'];
46385           } else if (dim === 4) {
46386             quadKeys = ['00', '01', '10', '11', '02', '03', '12', '13', '20', '21', '30', '31', '22', '23', '32', '33'];
46387           } else {
46388             // dim === 2
46389             quadKeys = ['0', '1', '2', '3'];
46390           }
46391
46392           return quadKeys;
46393         }
46394
46395         var serviceStreetside = {
46396           /**
46397            * init() initialize streetside.
46398            */
46399           init: function init() {
46400             if (!_ssCache) {
46401               this.reset();
46402             }
46403
46404             this.event = utilRebind(this, dispatch$7, 'on');
46405           },
46406
46407           /**
46408            * reset() reset the cache.
46409            */
46410           reset: function reset() {
46411             if (_ssCache) {
46412               Object.values(_ssCache.bubbles.inflight).forEach(abortRequest$6);
46413             }
46414
46415             _ssCache = {
46416               bubbles: {
46417                 inflight: {},
46418                 loaded: {},
46419                 nextPage: {},
46420                 rtree: new RBush(),
46421                 points: {},
46422                 leaders: []
46423               },
46424               sequences: {}
46425             };
46426           },
46427
46428           /**
46429            * bubbles()
46430            */
46431           bubbles: function bubbles(projection) {
46432             var limit = 5;
46433             return searchLimited$2(limit, projection, _ssCache.bubbles.rtree);
46434           },
46435           cachedImage: function cachedImage(imageKey) {
46436             return _ssCache.bubbles.points[imageKey];
46437           },
46438           sequences: function sequences(projection) {
46439             var viewport = projection.clipExtent();
46440             var min = [viewport[0][0], viewport[1][1]];
46441             var max = [viewport[1][0], viewport[0][1]];
46442             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
46443             var seen = {};
46444             var results = []; // all sequences for bubbles in viewport
46445
46446             _ssCache.bubbles.rtree.search(bbox).forEach(function (d) {
46447               var key = d.data.sequenceKey;
46448
46449               if (key && !seen[key]) {
46450                 seen[key] = true;
46451                 results.push(_ssCache.sequences[key].geojson);
46452               }
46453             });
46454
46455             return results;
46456           },
46457
46458           /**
46459            * loadBubbles()
46460            */
46461           loadBubbles: function loadBubbles(projection, margin) {
46462             // by default: request 2 nearby tiles so we can connect sequences.
46463             if (margin === undefined) margin = 2;
46464             loadTiles$2('bubbles', bubbleApi, projection, margin);
46465           },
46466           viewer: function viewer() {
46467             return _pannellumViewer;
46468           },
46469           initViewer: function initViewer() {
46470             if (!window.pannellum) return;
46471             if (_pannellumViewer) return;
46472             _currScene += 1;
46473
46474             var sceneID = _currScene.toString();
46475
46476             var options = {
46477               'default': {
46478                 firstScene: sceneID
46479               },
46480               scenes: {}
46481             };
46482             options.scenes[sceneID] = _sceneOptions;
46483             _pannellumViewer = window.pannellum.viewer('ideditor-viewer-streetside', options);
46484           },
46485           ensureViewerLoaded: function ensureViewerLoaded(context) {
46486             if (_loadViewerPromise$2) return _loadViewerPromise$2; // create ms-wrapper, a photo wrapper class
46487
46488             var wrap = context.container().select('.photoviewer').selectAll('.ms-wrapper').data([0]); // inject ms-wrapper into the photoviewer div
46489             // (used by all to house each custom photo viewer)
46490
46491             var wrapEnter = wrap.enter().append('div').attr('class', 'photo-wrapper ms-wrapper').classed('hide', true);
46492             var that = this;
46493             var pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // inject div to support streetside viewer (pannellum) and attribution line
46494
46495             wrapEnter.append('div').attr('id', 'ideditor-viewer-streetside').on(pointerPrefix + 'down.streetside', function () {
46496               select(window).on(pointerPrefix + 'move.streetside', function () {
46497                 dispatch$7.call('viewerChanged');
46498               }, true);
46499             }).on(pointerPrefix + 'up.streetside pointercancel.streetside', function () {
46500               select(window).on(pointerPrefix + 'move.streetside', null); // continue dispatching events for a few seconds, in case viewer has inertia.
46501
46502               var t = timer(function (elapsed) {
46503                 dispatch$7.call('viewerChanged');
46504
46505                 if (elapsed > 2000) {
46506                   t.stop();
46507                 }
46508               });
46509             }).append('div').attr('class', 'photo-attribution fillD');
46510             var controlsEnter = wrapEnter.append('div').attr('class', 'photo-controls-wrap').append('div').attr('class', 'photo-controls');
46511             controlsEnter.append('button').on('click.back', step(-1)).html('◄');
46512             controlsEnter.append('button').on('click.forward', step(1)).html('►'); // create working canvas for stitching together images
46513
46514             wrap = wrap.merge(wrapEnter).call(setupCanvas, true); // Register viewer resize handler
46515
46516             context.ui().photoviewer.on('resize.streetside', function () {
46517               if (_pannellumViewer) {
46518                 _pannellumViewer.resize();
46519               }
46520             });
46521             _loadViewerPromise$2 = new Promise(function (resolve, reject) {
46522               var loadedCount = 0;
46523
46524               function loaded() {
46525                 loadedCount += 1; // wait until both files are loaded
46526
46527                 if (loadedCount === 2) resolve();
46528               }
46529
46530               var head = select('head'); // load streetside pannellum viewer css
46531
46532               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 () {
46533                 reject();
46534               }); // load streetside pannellum viewer js
46535
46536               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 () {
46537                 reject();
46538               });
46539             })["catch"](function () {
46540               _loadViewerPromise$2 = null;
46541             });
46542             return _loadViewerPromise$2;
46543
46544             function step(stepBy) {
46545               return function () {
46546                 var viewer = context.container().select('.photoviewer');
46547                 var selected = viewer.empty() ? undefined : viewer.datum();
46548                 if (!selected) return;
46549                 var nextID = stepBy === 1 ? selected.ne : selected.pr;
46550
46551                 var yaw = _pannellumViewer.getYaw();
46552
46553                 var ca = selected.ca + yaw;
46554                 var origin = selected.loc; // construct a search trapezoid pointing out from current bubble
46555
46556                 var meters = 35;
46557                 var p1 = [origin[0] + geoMetersToLon(meters / 5, origin[1]), origin[1]];
46558                 var p2 = [origin[0] + geoMetersToLon(meters / 2, origin[1]), origin[1] + geoMetersToLat(meters)];
46559                 var p3 = [origin[0] - geoMetersToLon(meters / 2, origin[1]), origin[1] + geoMetersToLat(meters)];
46560                 var p4 = [origin[0] - geoMetersToLon(meters / 5, origin[1]), origin[1]];
46561                 var poly = [p1, p2, p3, p4, p1]; // rotate it to face forward/backward
46562
46563                 var angle = (stepBy === 1 ? ca : ca + 180) * (Math.PI / 180);
46564                 poly = geoRotate(poly, -angle, origin);
46565                 var extent = poly.reduce(function (extent, point) {
46566                   return extent.extend(geoExtent(point));
46567                 }, geoExtent()); // find nearest other bubble in the search polygon
46568
46569                 var minDist = Infinity;
46570
46571                 _ssCache.bubbles.rtree.search(extent.bbox()).forEach(function (d) {
46572                   if (d.data.key === selected.key) return;
46573                   if (!geoPointInPolygon(d.data.loc, poly)) return;
46574                   var dist = geoVecLength(d.data.loc, selected.loc);
46575                   var theta = selected.ca - d.data.ca;
46576                   var minTheta = Math.min(Math.abs(theta), 360 - Math.abs(theta));
46577
46578                   if (minTheta > 20) {
46579                     dist += 5; // penalize distance if camera angles don't match
46580                   }
46581
46582                   if (dist < minDist) {
46583                     nextID = d.data.key;
46584                     minDist = dist;
46585                   }
46586                 });
46587
46588                 var nextBubble = nextID && that.cachedImage(nextID);
46589                 if (!nextBubble) return;
46590                 context.map().centerEase(nextBubble.loc);
46591                 that.selectImage(context, nextBubble.key).yaw(yaw).showViewer(context);
46592               };
46593             }
46594           },
46595           yaw: function yaw(_yaw) {
46596             if (typeof _yaw !== 'number') return _yaw;
46597             _sceneOptions.yaw = _yaw;
46598             return this;
46599           },
46600
46601           /**
46602            * showViewer()
46603            */
46604           showViewer: function showViewer(context) {
46605             var wrap = context.container().select('.photoviewer').classed('hide', false);
46606             var isHidden = wrap.selectAll('.photo-wrapper.ms-wrapper.hide').size();
46607
46608             if (isHidden) {
46609               wrap.selectAll('.photo-wrapper:not(.ms-wrapper)').classed('hide', true);
46610               wrap.selectAll('.photo-wrapper.ms-wrapper').classed('hide', false);
46611             }
46612
46613             return this;
46614           },
46615
46616           /**
46617            * hideViewer()
46618            */
46619           hideViewer: function hideViewer(context) {
46620             var viewer = context.container().select('.photoviewer');
46621             if (!viewer.empty()) viewer.datum(null);
46622             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
46623             context.container().selectAll('.viewfield-group, .sequence, .icon-sign').classed('currentView', false);
46624             this.updateUrlImage(null);
46625             return this.setStyles(context, null, true);
46626           },
46627
46628           /**
46629            * selectImage().
46630            */
46631           selectImage: function selectImage(context, key) {
46632             var that = this;
46633             var d = this.cachedImage(key);
46634             var viewer = context.container().select('.photoviewer');
46635             if (!viewer.empty()) viewer.datum(d);
46636             this.setStyles(context, null, true);
46637             var wrap = context.container().select('.photoviewer .ms-wrapper');
46638             var attribution = wrap.selectAll('.photo-attribution').html('');
46639             wrap.selectAll('.pnlm-load-box') // display "loading.."
46640             .style('display', 'block');
46641             if (!d) return this;
46642             this.updateUrlImage(key);
46643             _sceneOptions.northOffset = d.ca;
46644             var line1 = attribution.append('div').attr('class', 'attribution-row');
46645             var hiresDomId = utilUniqueDomId('streetside-hires'); // Add hires checkbox
46646
46647             var label = line1.append('label').attr('for', hiresDomId).attr('class', 'streetside-hires');
46648             label.append('input').attr('type', 'checkbox').attr('id', hiresDomId).property('checked', _hires).on('click', function (d3_event) {
46649               d3_event.stopPropagation();
46650               _hires = !_hires;
46651               _resolution = _hires ? 1024 : 512;
46652               wrap.call(setupCanvas, true);
46653               var viewstate = {
46654                 yaw: _pannellumViewer.getYaw(),
46655                 pitch: _pannellumViewer.getPitch(),
46656                 hfov: _pannellumViewer.getHfov()
46657               };
46658               _sceneOptions = Object.assign(_sceneOptions, viewstate);
46659               that.selectImage(context, d.key).showViewer(context);
46660             });
46661             label.append('span').html(_t.html('streetside.hires'));
46662             var captureInfo = line1.append('div').attr('class', 'attribution-capture-info'); // Add capture date
46663
46664             if (d.captured_by) {
46665               var yyyy = new Date().getFullYear();
46666               captureInfo.append('a').attr('class', 'captured_by').attr('target', '_blank').attr('href', 'https://www.microsoft.com/en-us/maps/streetside').html('©' + yyyy + ' Microsoft');
46667               captureInfo.append('span').html('|');
46668             }
46669
46670             if (d.captured_at) {
46671               captureInfo.append('span').attr('class', 'captured_at').html(localeTimestamp(d.captured_at));
46672             } // Add image links
46673
46674
46675             var line2 = attribution.append('div').attr('class', 'attribution-row');
46676             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'));
46677             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'));
46678             var bubbleIdQuadKey = d.key.toString(4);
46679             var paddingNeeded = 16 - bubbleIdQuadKey.length;
46680
46681             for (var i = 0; i < paddingNeeded; i++) {
46682               bubbleIdQuadKey = '0' + bubbleIdQuadKey;
46683             }
46684
46685             var imgUrlPrefix = streetsideImagesApi + 'hs' + bubbleIdQuadKey;
46686             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
46687
46688             var faceKeys = ['01', '02', '03', '10', '11', '12']; // Map images to cube faces
46689
46690             var quadKeys = getQuadKeys();
46691             var faces = faceKeys.map(function (faceKey) {
46692               return quadKeys.map(function (quadKey) {
46693                 var xy = qkToXY(quadKey);
46694                 return {
46695                   face: faceKey,
46696                   url: imgUrlPrefix + faceKey + quadKey + imgUrlSuffix,
46697                   x: xy[0],
46698                   y: xy[1]
46699                 };
46700               });
46701             });
46702             loadFaces(faces).then(function () {
46703               if (!_pannellumViewer) {
46704                 that.initViewer();
46705               } else {
46706                 // make a new scene
46707                 _currScene += 1;
46708
46709                 var sceneID = _currScene.toString();
46710
46711                 _pannellumViewer.addScene(sceneID, _sceneOptions).loadScene(sceneID); // remove previous scene
46712
46713
46714                 if (_currScene > 2) {
46715                   sceneID = (_currScene - 1).toString();
46716
46717                   _pannellumViewer.removeScene(sceneID);
46718                 }
46719               }
46720             });
46721             return this;
46722           },
46723           getSequenceKeyForBubble: function getSequenceKeyForBubble(d) {
46724             return d && d.sequenceKey;
46725           },
46726           // Updates the currently highlighted sequence and selected bubble.
46727           // Reset is only necessary when interacting with the viewport because
46728           // this implicitly changes the currently selected bubble/sequence
46729           setStyles: function setStyles(context, hovered, reset) {
46730             if (reset) {
46731               // reset all layers
46732               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false).classed('currentView', false);
46733               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
46734             }
46735
46736             var hoveredBubbleKey = hovered && hovered.key;
46737             var hoveredSequenceKey = this.getSequenceKeyForBubble(hovered);
46738             var hoveredSequence = hoveredSequenceKey && _ssCache.sequences[hoveredSequenceKey];
46739             var hoveredBubbleKeys = hoveredSequence && hoveredSequence.bubbles.map(function (d) {
46740               return d.key;
46741             }) || [];
46742             var viewer = context.container().select('.photoviewer');
46743             var selected = viewer.empty() ? undefined : viewer.datum();
46744             var selectedBubbleKey = selected && selected.key;
46745             var selectedSequenceKey = this.getSequenceKeyForBubble(selected);
46746             var selectedSequence = selectedSequenceKey && _ssCache.sequences[selectedSequenceKey];
46747             var selectedBubbleKeys = selectedSequence && selectedSequence.bubbles.map(function (d) {
46748               return d.key;
46749             }) || []; // highlight sibling viewfields on either the selected or the hovered sequences
46750
46751             var highlightedBubbleKeys = utilArrayUnion(hoveredBubbleKeys, selectedBubbleKeys);
46752             context.container().selectAll('.layer-streetside-images .viewfield-group').classed('highlighted', function (d) {
46753               return highlightedBubbleKeys.indexOf(d.key) !== -1;
46754             }).classed('hovered', function (d) {
46755               return d.key === hoveredBubbleKey;
46756             }).classed('currentView', function (d) {
46757               return d.key === selectedBubbleKey;
46758             });
46759             context.container().selectAll('.layer-streetside-images .sequence').classed('highlighted', function (d) {
46760               return d.properties.key === hoveredSequenceKey;
46761             }).classed('currentView', function (d) {
46762               return d.properties.key === selectedSequenceKey;
46763             }); // update viewfields if needed
46764
46765             context.container().selectAll('.viewfield-group .viewfield').attr('d', viewfieldPath);
46766
46767             function viewfieldPath() {
46768               var d = this.parentNode.__data__;
46769
46770               if (d.pano && d.key !== selectedBubbleKey) {
46771                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
46772               } else {
46773                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
46774               }
46775             }
46776
46777             return this;
46778           },
46779           updateUrlImage: function updateUrlImage(imageKey) {
46780             if (!window.mocha) {
46781               var hash = utilStringQs(window.location.hash);
46782
46783               if (imageKey) {
46784                 hash.photo = 'streetside/' + imageKey;
46785               } else {
46786                 delete hash.photo;
46787               }
46788
46789               window.location.replace('#' + utilQsString(hash, true));
46790             }
46791           },
46792
46793           /**
46794            * cache().
46795            */
46796           cache: function cache() {
46797             return _ssCache;
46798           }
46799         };
46800
46801         var _apibase$1 = 'https://taginfo.openstreetmap.org/api/4/';
46802         var _inflight$2 = {};
46803         var _popularKeys = {};
46804         var _taginfoCache = {};
46805         var tag_sorts = {
46806           point: 'count_nodes',
46807           vertex: 'count_nodes',
46808           area: 'count_ways',
46809           line: 'count_ways'
46810         };
46811         var tag_sort_members = {
46812           point: 'count_node_members',
46813           vertex: 'count_node_members',
46814           area: 'count_way_members',
46815           line: 'count_way_members',
46816           relation: 'count_relation_members'
46817         };
46818         var tag_filters = {
46819           point: 'nodes',
46820           vertex: 'nodes',
46821           area: 'ways',
46822           line: 'ways'
46823         };
46824         var tag_members_fractions = {
46825           point: 'count_node_members_fraction',
46826           vertex: 'count_node_members_fraction',
46827           area: 'count_way_members_fraction',
46828           line: 'count_way_members_fraction',
46829           relation: 'count_relation_members_fraction'
46830         };
46831
46832         function sets(params, n, o) {
46833           if (params.geometry && o[params.geometry]) {
46834             params[n] = o[params.geometry];
46835           }
46836
46837           return params;
46838         }
46839
46840         function setFilter(params) {
46841           return sets(params, 'filter', tag_filters);
46842         }
46843
46844         function setSort(params) {
46845           return sets(params, 'sortname', tag_sorts);
46846         }
46847
46848         function setSortMembers(params) {
46849           return sets(params, 'sortname', tag_sort_members);
46850         }
46851
46852         function clean(params) {
46853           return utilObjectOmit(params, ['geometry', 'debounce']);
46854         }
46855
46856         function filterKeys(type) {
46857           var count_type = type ? 'count_' + type : 'count_all';
46858           return function (d) {
46859             return parseFloat(d[count_type]) > 2500 || d.in_wiki;
46860           };
46861         }
46862
46863         function filterMultikeys(prefix) {
46864           return function (d) {
46865             // d.key begins with prefix, and d.key contains no additional ':'s
46866             var re = new RegExp('^' + prefix + '(.*)$');
46867             var matches = d.key.match(re) || [];
46868             return matches.length === 2 && matches[1].indexOf(':') === -1;
46869           };
46870         }
46871
46872         function filterValues(allowUpperCase) {
46873           return function (d) {
46874             if (d.value.match(/[;,]/) !== null) return false; // exclude some punctuation
46875
46876             if (!allowUpperCase && d.value.match(/[A-Z*]/) !== null) return false; // exclude uppercase letters
46877
46878             return parseFloat(d.fraction) > 0.0;
46879           };
46880         }
46881
46882         function filterRoles(geometry) {
46883           return function (d) {
46884             if (d.role === '') return false; // exclude empty role
46885
46886             if (d.role.match(/[A-Z*;,]/) !== null) return false; // exclude uppercase letters and some punctuation
46887
46888             return parseFloat(d[tag_members_fractions[geometry]]) > 0.0;
46889           };
46890         }
46891
46892         function valKey(d) {
46893           return {
46894             value: d.key,
46895             title: d.key
46896           };
46897         }
46898
46899         function valKeyDescription(d) {
46900           var obj = {
46901             value: d.value,
46902             title: d.description || d.value
46903           };
46904
46905           if (d.count) {
46906             obj.count = d.count;
46907           }
46908
46909           return obj;
46910         }
46911
46912         function roleKey(d) {
46913           return {
46914             value: d.role,
46915             title: d.role
46916           };
46917         } // sort keys with ':' lower than keys without ':'
46918
46919
46920         function sortKeys(a, b) {
46921           return a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1 ? -1 : a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1 ? 1 : 0;
46922         }
46923
46924         var debouncedRequest$1 = debounce(request$1, 300, {
46925           leading: false
46926         });
46927
46928         function request$1(url, params, exactMatch, callback, loaded) {
46929           if (_inflight$2[url]) return;
46930           if (checkCache(url, params, exactMatch, callback)) return;
46931           var controller = new AbortController();
46932           _inflight$2[url] = controller;
46933           d3_json(url, {
46934             signal: controller.signal
46935           }).then(function (result) {
46936             delete _inflight$2[url];
46937             if (loaded) loaded(null, result);
46938           })["catch"](function (err) {
46939             delete _inflight$2[url];
46940             if (err.name === 'AbortError') return;
46941             if (loaded) loaded(err.message);
46942           });
46943         }
46944
46945         function checkCache(url, params, exactMatch, callback) {
46946           var rp = params.rp || 25;
46947           var testQuery = params.query || '';
46948           var testUrl = url;
46949
46950           do {
46951             var hit = _taginfoCache[testUrl]; // exact match, or shorter match yielding fewer than max results (rp)
46952
46953             if (hit && (url === testUrl || hit.length < rp)) {
46954               callback(null, hit);
46955               return true;
46956             } // don't try to shorten the query
46957
46958
46959             if (exactMatch || !testQuery.length) return false; // do shorten the query to see if we already have a cached result
46960             // that has returned fewer than max results (rp)
46961
46962             testQuery = testQuery.slice(0, -1);
46963             testUrl = url.replace(/&query=(.*?)&/, '&query=' + testQuery + '&');
46964           } while (testQuery.length >= 0);
46965
46966           return false;
46967         }
46968
46969         var serviceTaginfo = {
46970           init: function init() {
46971             _inflight$2 = {};
46972             _taginfoCache = {};
46973             _popularKeys = {
46974               // manually exclude some keys – #5377, #7485
46975               postal_code: true,
46976               full_name: true,
46977               loc_name: true,
46978               reg_name: true,
46979               short_name: true,
46980               sorting_name: true,
46981               artist_name: true,
46982               nat_name: true,
46983               long_name: true,
46984               'bridge:name': true
46985             }; // Fetch popular keys.  We'll exclude these from `values`
46986             // lookups because they stress taginfo, and they aren't likely
46987             // to yield meaningful autocomplete results.. see #3955
46988
46989             var params = {
46990               rp: 100,
46991               sortname: 'values_all',
46992               sortorder: 'desc',
46993               page: 1,
46994               debounce: false,
46995               lang: _mainLocalizer.languageCode()
46996             };
46997             this.keys(params, function (err, data) {
46998               if (err) return;
46999               data.forEach(function (d) {
47000                 if (d.value === 'opening_hours') return; // exception
47001
47002                 _popularKeys[d.value] = true;
47003               });
47004             });
47005           },
47006           reset: function reset() {
47007             Object.values(_inflight$2).forEach(function (controller) {
47008               controller.abort();
47009             });
47010             _inflight$2 = {};
47011           },
47012           keys: function keys(params, callback) {
47013             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47014             params = clean(setSort(params));
47015             params = Object.assign({
47016               rp: 10,
47017               sortname: 'count_all',
47018               sortorder: 'desc',
47019               page: 1,
47020               lang: _mainLocalizer.languageCode()
47021             }, params);
47022             var url = _apibase$1 + 'keys/all?' + utilQsString(params);
47023             doRequest(url, params, false, callback, function (err, d) {
47024               if (err) {
47025                 callback(err);
47026               } else {
47027                 var f = filterKeys(params.filter);
47028                 var result = d.data.filter(f).sort(sortKeys).map(valKey);
47029                 _taginfoCache[url] = result;
47030                 callback(null, result);
47031               }
47032             });
47033           },
47034           multikeys: function multikeys(params, callback) {
47035             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47036             params = clean(setSort(params));
47037             params = Object.assign({
47038               rp: 25,
47039               sortname: 'count_all',
47040               sortorder: 'desc',
47041               page: 1,
47042               lang: _mainLocalizer.languageCode()
47043             }, params);
47044             var prefix = params.query;
47045             var url = _apibase$1 + 'keys/all?' + utilQsString(params);
47046             doRequest(url, params, true, callback, function (err, d) {
47047               if (err) {
47048                 callback(err);
47049               } else {
47050                 var f = filterMultikeys(prefix);
47051                 var result = d.data.filter(f).map(valKey);
47052                 _taginfoCache[url] = result;
47053                 callback(null, result);
47054               }
47055             });
47056           },
47057           values: function values(params, callback) {
47058             // Exclude popular keys from values lookups.. see #3955
47059             var key = params.key;
47060
47061             if (key && _popularKeys[key]) {
47062               callback(null, []);
47063               return;
47064             }
47065
47066             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47067             params = clean(setSort(setFilter(params)));
47068             params = Object.assign({
47069               rp: 25,
47070               sortname: 'count_all',
47071               sortorder: 'desc',
47072               page: 1,
47073               lang: _mainLocalizer.languageCode()
47074             }, params);
47075             var url = _apibase$1 + 'key/values?' + utilQsString(params);
47076             doRequest(url, params, false, callback, function (err, d) {
47077               if (err) {
47078                 callback(err);
47079               } else {
47080                 // In most cases we prefer taginfo value results with lowercase letters.
47081                 // A few OSM keys expect values to contain uppercase values (see #3377).
47082                 // This is not an exhaustive list (e.g. `name` also has uppercase values)
47083                 // but these are the fields where taginfo value lookup is most useful.
47084                 var re = /network|taxon|genus|species|brand|grape_variety|royal_cypher|listed_status|booth|rating|stars|:output|_hours|_times|_ref|manufacturer|country|target|brewery/;
47085                 var allowUpperCase = re.test(params.key);
47086                 var f = filterValues(allowUpperCase);
47087                 var result = d.data.filter(f).map(valKeyDescription);
47088                 _taginfoCache[url] = result;
47089                 callback(null, result);
47090               }
47091             });
47092           },
47093           roles: function roles(params, callback) {
47094             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47095             var geometry = params.geometry;
47096             params = clean(setSortMembers(params));
47097             params = Object.assign({
47098               rp: 25,
47099               sortname: 'count_all_members',
47100               sortorder: 'desc',
47101               page: 1,
47102               lang: _mainLocalizer.languageCode()
47103             }, params);
47104             var url = _apibase$1 + 'relation/roles?' + utilQsString(params);
47105             doRequest(url, params, true, callback, function (err, d) {
47106               if (err) {
47107                 callback(err);
47108               } else {
47109                 var f = filterRoles(geometry);
47110                 var result = d.data.filter(f).map(roleKey);
47111                 _taginfoCache[url] = result;
47112                 callback(null, result);
47113               }
47114             });
47115           },
47116           docs: function docs(params, callback) {
47117             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47118             params = clean(setSort(params));
47119             var path = 'key/wiki_pages?';
47120
47121             if (params.value) {
47122               path = 'tag/wiki_pages?';
47123             } else if (params.rtype) {
47124               path = 'relation/wiki_pages?';
47125             }
47126
47127             var url = _apibase$1 + path + utilQsString(params);
47128             doRequest(url, params, true, callback, function (err, d) {
47129               if (err) {
47130                 callback(err);
47131               } else {
47132                 _taginfoCache[url] = d.data;
47133                 callback(null, d.data);
47134               }
47135             });
47136           },
47137           apibase: function apibase(_) {
47138             if (!arguments.length) return _apibase$1;
47139             _apibase$1 = _;
47140             return this;
47141           }
47142         };
47143
47144         var helpers$1 = createCommonjsModule(function (module, exports) {
47145
47146           Object.defineProperty(exports, "__esModule", {
47147             value: true
47148           });
47149           /**
47150            * @module helpers
47151            */
47152
47153           /**
47154            * Earth Radius used with the Harvesine formula and approximates using a spherical (non-ellipsoid) Earth.
47155            *
47156            * @memberof helpers
47157            * @type {number}
47158            */
47159
47160           exports.earthRadius = 6371008.8;
47161           /**
47162            * Unit of measurement factors using a spherical (non-ellipsoid) earth radius.
47163            *
47164            * @memberof helpers
47165            * @type {Object}
47166            */
47167
47168           exports.factors = {
47169             centimeters: exports.earthRadius * 100,
47170             centimetres: exports.earthRadius * 100,
47171             degrees: exports.earthRadius / 111325,
47172             feet: exports.earthRadius * 3.28084,
47173             inches: exports.earthRadius * 39.370,
47174             kilometers: exports.earthRadius / 1000,
47175             kilometres: exports.earthRadius / 1000,
47176             meters: exports.earthRadius,
47177             metres: exports.earthRadius,
47178             miles: exports.earthRadius / 1609.344,
47179             millimeters: exports.earthRadius * 1000,
47180             millimetres: exports.earthRadius * 1000,
47181             nauticalmiles: exports.earthRadius / 1852,
47182             radians: 1,
47183             yards: exports.earthRadius / 1.0936
47184           };
47185           /**
47186            * Units of measurement factors based on 1 meter.
47187            *
47188            * @memberof helpers
47189            * @type {Object}
47190            */
47191
47192           exports.unitsFactors = {
47193             centimeters: 100,
47194             centimetres: 100,
47195             degrees: 1 / 111325,
47196             feet: 3.28084,
47197             inches: 39.370,
47198             kilometers: 1 / 1000,
47199             kilometres: 1 / 1000,
47200             meters: 1,
47201             metres: 1,
47202             miles: 1 / 1609.344,
47203             millimeters: 1000,
47204             millimetres: 1000,
47205             nauticalmiles: 1 / 1852,
47206             radians: 1 / exports.earthRadius,
47207             yards: 1 / 1.0936
47208           };
47209           /**
47210            * Area of measurement factors based on 1 square meter.
47211            *
47212            * @memberof helpers
47213            * @type {Object}
47214            */
47215
47216           exports.areaFactors = {
47217             acres: 0.000247105,
47218             centimeters: 10000,
47219             centimetres: 10000,
47220             feet: 10.763910417,
47221             inches: 1550.003100006,
47222             kilometers: 0.000001,
47223             kilometres: 0.000001,
47224             meters: 1,
47225             metres: 1,
47226             miles: 3.86e-7,
47227             millimeters: 1000000,
47228             millimetres: 1000000,
47229             yards: 1.195990046
47230           };
47231           /**
47232            * Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}.
47233            *
47234            * @name feature
47235            * @param {Geometry} geometry input geometry
47236            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47237            * @param {Object} [options={}] Optional Parameters
47238            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47239            * @param {string|number} [options.id] Identifier associated with the Feature
47240            * @returns {Feature} a GeoJSON Feature
47241            * @example
47242            * var geometry = {
47243            *   "type": "Point",
47244            *   "coordinates": [110, 50]
47245            * };
47246            *
47247            * var feature = turf.feature(geometry);
47248            *
47249            * //=feature
47250            */
47251
47252           function feature(geom, properties, options) {
47253             if (options === void 0) {
47254               options = {};
47255             }
47256
47257             var feat = {
47258               type: "Feature"
47259             };
47260
47261             if (options.id === 0 || options.id) {
47262               feat.id = options.id;
47263             }
47264
47265             if (options.bbox) {
47266               feat.bbox = options.bbox;
47267             }
47268
47269             feat.properties = properties || {};
47270             feat.geometry = geom;
47271             return feat;
47272           }
47273
47274           exports.feature = feature;
47275           /**
47276            * Creates a GeoJSON {@link Geometry} from a Geometry string type & coordinates.
47277            * For GeometryCollection type use `helpers.geometryCollection`
47278            *
47279            * @name geometry
47280            * @param {string} type Geometry Type
47281            * @param {Array<any>} coordinates Coordinates
47282            * @param {Object} [options={}] Optional Parameters
47283            * @returns {Geometry} a GeoJSON Geometry
47284            * @example
47285            * var type = "Point";
47286            * var coordinates = [110, 50];
47287            * var geometry = turf.geometry(type, coordinates);
47288            * // => geometry
47289            */
47290
47291           function geometry(type, coordinates, options) {
47292
47293             switch (type) {
47294               case "Point":
47295                 return point(coordinates).geometry;
47296
47297               case "LineString":
47298                 return lineString(coordinates).geometry;
47299
47300               case "Polygon":
47301                 return polygon(coordinates).geometry;
47302
47303               case "MultiPoint":
47304                 return multiPoint(coordinates).geometry;
47305
47306               case "MultiLineString":
47307                 return multiLineString(coordinates).geometry;
47308
47309               case "MultiPolygon":
47310                 return multiPolygon(coordinates).geometry;
47311
47312               default:
47313                 throw new Error(type + " is invalid");
47314             }
47315           }
47316
47317           exports.geometry = geometry;
47318           /**
47319            * Creates a {@link Point} {@link Feature} from a Position.
47320            *
47321            * @name point
47322            * @param {Array<number>} coordinates longitude, latitude position (each in decimal degrees)
47323            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47324            * @param {Object} [options={}] Optional Parameters
47325            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47326            * @param {string|number} [options.id] Identifier associated with the Feature
47327            * @returns {Feature<Point>} a Point feature
47328            * @example
47329            * var point = turf.point([-75.343, 39.984]);
47330            *
47331            * //=point
47332            */
47333
47334           function point(coordinates, properties, options) {
47335             if (options === void 0) {
47336               options = {};
47337             }
47338
47339             var geom = {
47340               type: "Point",
47341               coordinates: coordinates
47342             };
47343             return feature(geom, properties, options);
47344           }
47345
47346           exports.point = point;
47347           /**
47348            * Creates a {@link Point} {@link FeatureCollection} from an Array of Point coordinates.
47349            *
47350            * @name points
47351            * @param {Array<Array<number>>} coordinates an array of Points
47352            * @param {Object} [properties={}] Translate these properties to each Feature
47353            * @param {Object} [options={}] Optional Parameters
47354            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north]
47355            * associated with the FeatureCollection
47356            * @param {string|number} [options.id] Identifier associated with the FeatureCollection
47357            * @returns {FeatureCollection<Point>} Point Feature
47358            * @example
47359            * var points = turf.points([
47360            *   [-75, 39],
47361            *   [-80, 45],
47362            *   [-78, 50]
47363            * ]);
47364            *
47365            * //=points
47366            */
47367
47368           function points(coordinates, properties, options) {
47369             if (options === void 0) {
47370               options = {};
47371             }
47372
47373             return featureCollection(coordinates.map(function (coords) {
47374               return point(coords, properties);
47375             }), options);
47376           }
47377
47378           exports.points = points;
47379           /**
47380            * Creates a {@link Polygon} {@link Feature} from an Array of LinearRings.
47381            *
47382            * @name polygon
47383            * @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
47384            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47385            * @param {Object} [options={}] Optional Parameters
47386            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47387            * @param {string|number} [options.id] Identifier associated with the Feature
47388            * @returns {Feature<Polygon>} Polygon Feature
47389            * @example
47390            * var polygon = turf.polygon([[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]], { name: 'poly1' });
47391            *
47392            * //=polygon
47393            */
47394
47395           function polygon(coordinates, properties, options) {
47396             if (options === void 0) {
47397               options = {};
47398             }
47399
47400             for (var _i = 0, coordinates_1 = coordinates; _i < coordinates_1.length; _i++) {
47401               var ring = coordinates_1[_i];
47402
47403               if (ring.length < 4) {
47404                 throw new Error("Each LinearRing of a Polygon must have 4 or more Positions.");
47405               }
47406
47407               for (var j = 0; j < ring[ring.length - 1].length; j++) {
47408                 // Check if first point of Polygon contains two numbers
47409                 if (ring[ring.length - 1][j] !== ring[0][j]) {
47410                   throw new Error("First and last Position are not equivalent.");
47411                 }
47412               }
47413             }
47414
47415             var geom = {
47416               type: "Polygon",
47417               coordinates: coordinates
47418             };
47419             return feature(geom, properties, options);
47420           }
47421
47422           exports.polygon = polygon;
47423           /**
47424            * Creates a {@link Polygon} {@link FeatureCollection} from an Array of Polygon coordinates.
47425            *
47426            * @name polygons
47427            * @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygon coordinates
47428            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47429            * @param {Object} [options={}] Optional Parameters
47430            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47431            * @param {string|number} [options.id] Identifier associated with the FeatureCollection
47432            * @returns {FeatureCollection<Polygon>} Polygon FeatureCollection
47433            * @example
47434            * var polygons = turf.polygons([
47435            *   [[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]],
47436            *   [[[-15, 42], [-14, 46], [-12, 41], [-17, 44], [-15, 42]]],
47437            * ]);
47438            *
47439            * //=polygons
47440            */
47441
47442           function polygons(coordinates, properties, options) {
47443             if (options === void 0) {
47444               options = {};
47445             }
47446
47447             return featureCollection(coordinates.map(function (coords) {
47448               return polygon(coords, properties);
47449             }), options);
47450           }
47451
47452           exports.polygons = polygons;
47453           /**
47454            * Creates a {@link LineString} {@link Feature} from an Array of Positions.
47455            *
47456            * @name lineString
47457            * @param {Array<Array<number>>} coordinates an array of Positions
47458            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47459            * @param {Object} [options={}] Optional Parameters
47460            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47461            * @param {string|number} [options.id] Identifier associated with the Feature
47462            * @returns {Feature<LineString>} LineString Feature
47463            * @example
47464            * var linestring1 = turf.lineString([[-24, 63], [-23, 60], [-25, 65], [-20, 69]], {name: 'line 1'});
47465            * var linestring2 = turf.lineString([[-14, 43], [-13, 40], [-15, 45], [-10, 49]], {name: 'line 2'});
47466            *
47467            * //=linestring1
47468            * //=linestring2
47469            */
47470
47471           function lineString(coordinates, properties, options) {
47472             if (options === void 0) {
47473               options = {};
47474             }
47475
47476             if (coordinates.length < 2) {
47477               throw new Error("coordinates must be an array of two or more positions");
47478             }
47479
47480             var geom = {
47481               type: "LineString",
47482               coordinates: coordinates
47483             };
47484             return feature(geom, properties, options);
47485           }
47486
47487           exports.lineString = lineString;
47488           /**
47489            * Creates a {@link LineString} {@link FeatureCollection} from an Array of LineString coordinates.
47490            *
47491            * @name lineStrings
47492            * @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
47493            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47494            * @param {Object} [options={}] Optional Parameters
47495            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north]
47496            * associated with the FeatureCollection
47497            * @param {string|number} [options.id] Identifier associated with the FeatureCollection
47498            * @returns {FeatureCollection<LineString>} LineString FeatureCollection
47499            * @example
47500            * var linestrings = turf.lineStrings([
47501            *   [[-24, 63], [-23, 60], [-25, 65], [-20, 69]],
47502            *   [[-14, 43], [-13, 40], [-15, 45], [-10, 49]]
47503            * ]);
47504            *
47505            * //=linestrings
47506            */
47507
47508           function lineStrings(coordinates, properties, options) {
47509             if (options === void 0) {
47510               options = {};
47511             }
47512
47513             return featureCollection(coordinates.map(function (coords) {
47514               return lineString(coords, properties);
47515             }), options);
47516           }
47517
47518           exports.lineStrings = lineStrings;
47519           /**
47520            * Takes one or more {@link Feature|Features} and creates a {@link FeatureCollection}.
47521            *
47522            * @name featureCollection
47523            * @param {Feature[]} features input features
47524            * @param {Object} [options={}] Optional Parameters
47525            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47526            * @param {string|number} [options.id] Identifier associated with the Feature
47527            * @returns {FeatureCollection} FeatureCollection of Features
47528            * @example
47529            * var locationA = turf.point([-75.343, 39.984], {name: 'Location A'});
47530            * var locationB = turf.point([-75.833, 39.284], {name: 'Location B'});
47531            * var locationC = turf.point([-75.534, 39.123], {name: 'Location C'});
47532            *
47533            * var collection = turf.featureCollection([
47534            *   locationA,
47535            *   locationB,
47536            *   locationC
47537            * ]);
47538            *
47539            * //=collection
47540            */
47541
47542           function featureCollection(features, options) {
47543             if (options === void 0) {
47544               options = {};
47545             }
47546
47547             var fc = {
47548               type: "FeatureCollection"
47549             };
47550
47551             if (options.id) {
47552               fc.id = options.id;
47553             }
47554
47555             if (options.bbox) {
47556               fc.bbox = options.bbox;
47557             }
47558
47559             fc.features = features;
47560             return fc;
47561           }
47562
47563           exports.featureCollection = featureCollection;
47564           /**
47565            * Creates a {@link Feature<MultiLineString>} based on a
47566            * coordinate array. Properties can be added optionally.
47567            *
47568            * @name multiLineString
47569            * @param {Array<Array<Array<number>>>} coordinates an array of LineStrings
47570            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47571            * @param {Object} [options={}] Optional Parameters
47572            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47573            * @param {string|number} [options.id] Identifier associated with the Feature
47574            * @returns {Feature<MultiLineString>} a MultiLineString feature
47575            * @throws {Error} if no coordinates are passed
47576            * @example
47577            * var multiLine = turf.multiLineString([[[0,0],[10,10]]]);
47578            *
47579            * //=multiLine
47580            */
47581
47582           function multiLineString(coordinates, properties, options) {
47583             if (options === void 0) {
47584               options = {};
47585             }
47586
47587             var geom = {
47588               type: "MultiLineString",
47589               coordinates: coordinates
47590             };
47591             return feature(geom, properties, options);
47592           }
47593
47594           exports.multiLineString = multiLineString;
47595           /**
47596            * Creates a {@link Feature<MultiPoint>} based on a
47597            * coordinate array. Properties can be added optionally.
47598            *
47599            * @name multiPoint
47600            * @param {Array<Array<number>>} coordinates an array of Positions
47601            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47602            * @param {Object} [options={}] Optional Parameters
47603            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47604            * @param {string|number} [options.id] Identifier associated with the Feature
47605            * @returns {Feature<MultiPoint>} a MultiPoint feature
47606            * @throws {Error} if no coordinates are passed
47607            * @example
47608            * var multiPt = turf.multiPoint([[0,0],[10,10]]);
47609            *
47610            * //=multiPt
47611            */
47612
47613           function multiPoint(coordinates, properties, options) {
47614             if (options === void 0) {
47615               options = {};
47616             }
47617
47618             var geom = {
47619               type: "MultiPoint",
47620               coordinates: coordinates
47621             };
47622             return feature(geom, properties, options);
47623           }
47624
47625           exports.multiPoint = multiPoint;
47626           /**
47627            * Creates a {@link Feature<MultiPolygon>} based on a
47628            * coordinate array. Properties can be added optionally.
47629            *
47630            * @name multiPolygon
47631            * @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygons
47632            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47633            * @param {Object} [options={}] Optional Parameters
47634            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47635            * @param {string|number} [options.id] Identifier associated with the Feature
47636            * @returns {Feature<MultiPolygon>} a multipolygon feature
47637            * @throws {Error} if no coordinates are passed
47638            * @example
47639            * var multiPoly = turf.multiPolygon([[[[0,0],[0,10],[10,10],[10,0],[0,0]]]]);
47640            *
47641            * //=multiPoly
47642            *
47643            */
47644
47645           function multiPolygon(coordinates, properties, options) {
47646             if (options === void 0) {
47647               options = {};
47648             }
47649
47650             var geom = {
47651               type: "MultiPolygon",
47652               coordinates: coordinates
47653             };
47654             return feature(geom, properties, options);
47655           }
47656
47657           exports.multiPolygon = multiPolygon;
47658           /**
47659            * Creates a {@link Feature<GeometryCollection>} based on a
47660            * coordinate array. Properties can be added optionally.
47661            *
47662            * @name geometryCollection
47663            * @param {Array<Geometry>} geometries an array of GeoJSON Geometries
47664            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47665            * @param {Object} [options={}] Optional Parameters
47666            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47667            * @param {string|number} [options.id] Identifier associated with the Feature
47668            * @returns {Feature<GeometryCollection>} a GeoJSON GeometryCollection Feature
47669            * @example
47670            * var pt = turf.geometry("Point", [100, 0]);
47671            * var line = turf.geometry("LineString", [[101, 0], [102, 1]]);
47672            * var collection = turf.geometryCollection([pt, line]);
47673            *
47674            * // => collection
47675            */
47676
47677           function geometryCollection(geometries, properties, options) {
47678             if (options === void 0) {
47679               options = {};
47680             }
47681
47682             var geom = {
47683               type: "GeometryCollection",
47684               geometries: geometries
47685             };
47686             return feature(geom, properties, options);
47687           }
47688
47689           exports.geometryCollection = geometryCollection;
47690           /**
47691            * Round number to precision
47692            *
47693            * @param {number} num Number
47694            * @param {number} [precision=0] Precision
47695            * @returns {number} rounded number
47696            * @example
47697            * turf.round(120.4321)
47698            * //=120
47699            *
47700            * turf.round(120.4321, 2)
47701            * //=120.43
47702            */
47703
47704           function round(num, precision) {
47705             if (precision === void 0) {
47706               precision = 0;
47707             }
47708
47709             if (precision && !(precision >= 0)) {
47710               throw new Error("precision must be a positive number");
47711             }
47712
47713             var multiplier = Math.pow(10, precision || 0);
47714             return Math.round(num * multiplier) / multiplier;
47715           }
47716
47717           exports.round = round;
47718           /**
47719            * Convert a distance measurement (assuming a spherical Earth) from radians to a more friendly unit.
47720            * Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
47721            *
47722            * @name radiansToLength
47723            * @param {number} radians in radians across the sphere
47724            * @param {string} [units="kilometers"] can be degrees, radians, miles, or kilometers inches, yards, metres,
47725            * meters, kilometres, kilometers.
47726            * @returns {number} distance
47727            */
47728
47729           function radiansToLength(radians, units) {
47730             if (units === void 0) {
47731               units = "kilometers";
47732             }
47733
47734             var factor = exports.factors[units];
47735
47736             if (!factor) {
47737               throw new Error(units + " units is invalid");
47738             }
47739
47740             return radians * factor;
47741           }
47742
47743           exports.radiansToLength = radiansToLength;
47744           /**
47745            * Convert a distance measurement (assuming a spherical Earth) from a real-world unit into radians
47746            * Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
47747            *
47748            * @name lengthToRadians
47749            * @param {number} distance in real units
47750            * @param {string} [units="kilometers"] can be degrees, radians, miles, or kilometers inches, yards, metres,
47751            * meters, kilometres, kilometers.
47752            * @returns {number} radians
47753            */
47754
47755           function lengthToRadians(distance, units) {
47756             if (units === void 0) {
47757               units = "kilometers";
47758             }
47759
47760             var factor = exports.factors[units];
47761
47762             if (!factor) {
47763               throw new Error(units + " units is invalid");
47764             }
47765
47766             return distance / factor;
47767           }
47768
47769           exports.lengthToRadians = lengthToRadians;
47770           /**
47771            * Convert a distance measurement (assuming a spherical Earth) from a real-world unit into degrees
47772            * Valid units: miles, nauticalmiles, inches, yards, meters, metres, centimeters, kilometres, feet
47773            *
47774            * @name lengthToDegrees
47775            * @param {number} distance in real units
47776            * @param {string} [units="kilometers"] can be degrees, radians, miles, or kilometers inches, yards, metres,
47777            * meters, kilometres, kilometers.
47778            * @returns {number} degrees
47779            */
47780
47781           function lengthToDegrees(distance, units) {
47782             return radiansToDegrees(lengthToRadians(distance, units));
47783           }
47784
47785           exports.lengthToDegrees = lengthToDegrees;
47786           /**
47787            * Converts any bearing angle from the north line direction (positive clockwise)
47788            * and returns an angle between 0-360 degrees (positive clockwise), 0 being the north line
47789            *
47790            * @name bearingToAzimuth
47791            * @param {number} bearing angle, between -180 and +180 degrees
47792            * @returns {number} angle between 0 and 360 degrees
47793            */
47794
47795           function bearingToAzimuth(bearing) {
47796             var angle = bearing % 360;
47797
47798             if (angle < 0) {
47799               angle += 360;
47800             }
47801
47802             return angle;
47803           }
47804
47805           exports.bearingToAzimuth = bearingToAzimuth;
47806           /**
47807            * Converts an angle in radians to degrees
47808            *
47809            * @name radiansToDegrees
47810            * @param {number} radians angle in radians
47811            * @returns {number} degrees between 0 and 360 degrees
47812            */
47813
47814           function radiansToDegrees(radians) {
47815             var degrees = radians % (2 * Math.PI);
47816             return degrees * 180 / Math.PI;
47817           }
47818
47819           exports.radiansToDegrees = radiansToDegrees;
47820           /**
47821            * Converts an angle in degrees to radians
47822            *
47823            * @name degreesToRadians
47824            * @param {number} degrees angle between 0 and 360 degrees
47825            * @returns {number} angle in radians
47826            */
47827
47828           function degreesToRadians(degrees) {
47829             var radians = degrees % 360;
47830             return radians * Math.PI / 180;
47831           }
47832
47833           exports.degreesToRadians = degreesToRadians;
47834           /**
47835            * Converts a length to the requested unit.
47836            * Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
47837            *
47838            * @param {number} length to be converted
47839            * @param {Units} [originalUnit="kilometers"] of the length
47840            * @param {Units} [finalUnit="kilometers"] returned unit
47841            * @returns {number} the converted length
47842            */
47843
47844           function convertLength(length, originalUnit, finalUnit) {
47845             if (originalUnit === void 0) {
47846               originalUnit = "kilometers";
47847             }
47848
47849             if (finalUnit === void 0) {
47850               finalUnit = "kilometers";
47851             }
47852
47853             if (!(length >= 0)) {
47854               throw new Error("length must be a positive number");
47855             }
47856
47857             return radiansToLength(lengthToRadians(length, originalUnit), finalUnit);
47858           }
47859
47860           exports.convertLength = convertLength;
47861           /**
47862            * Converts a area to the requested unit.
47863            * Valid units: kilometers, kilometres, meters, metres, centimetres, millimeters, acres, miles, yards, feet, inches
47864            * @param {number} area to be converted
47865            * @param {Units} [originalUnit="meters"] of the distance
47866            * @param {Units} [finalUnit="kilometers"] returned unit
47867            * @returns {number} the converted distance
47868            */
47869
47870           function convertArea(area, originalUnit, finalUnit) {
47871             if (originalUnit === void 0) {
47872               originalUnit = "meters";
47873             }
47874
47875             if (finalUnit === void 0) {
47876               finalUnit = "kilometers";
47877             }
47878
47879             if (!(area >= 0)) {
47880               throw new Error("area must be a positive number");
47881             }
47882
47883             var startFactor = exports.areaFactors[originalUnit];
47884
47885             if (!startFactor) {
47886               throw new Error("invalid original units");
47887             }
47888
47889             var finalFactor = exports.areaFactors[finalUnit];
47890
47891             if (!finalFactor) {
47892               throw new Error("invalid final units");
47893             }
47894
47895             return area / startFactor * finalFactor;
47896           }
47897
47898           exports.convertArea = convertArea;
47899           /**
47900            * isNumber
47901            *
47902            * @param {*} num Number to validate
47903            * @returns {boolean} true/false
47904            * @example
47905            * turf.isNumber(123)
47906            * //=true
47907            * turf.isNumber('foo')
47908            * //=false
47909            */
47910
47911           function isNumber(num) {
47912             return !isNaN(num) && num !== null && !Array.isArray(num) && !/^\s*$/.test(num);
47913           }
47914
47915           exports.isNumber = isNumber;
47916           /**
47917            * isObject
47918            *
47919            * @param {*} input variable to validate
47920            * @returns {boolean} true/false
47921            * @example
47922            * turf.isObject({elevation: 10})
47923            * //=true
47924            * turf.isObject('foo')
47925            * //=false
47926            */
47927
47928           function isObject(input) {
47929             return !!input && input.constructor === Object;
47930           }
47931
47932           exports.isObject = isObject;
47933           /**
47934            * Validate BBox
47935            *
47936            * @private
47937            * @param {Array<number>} bbox BBox to validate
47938            * @returns {void}
47939            * @throws Error if BBox is not valid
47940            * @example
47941            * validateBBox([-180, -40, 110, 50])
47942            * //=OK
47943            * validateBBox([-180, -40])
47944            * //=Error
47945            * validateBBox('Foo')
47946            * //=Error
47947            * validateBBox(5)
47948            * //=Error
47949            * validateBBox(null)
47950            * //=Error
47951            * validateBBox(undefined)
47952            * //=Error
47953            */
47954
47955           function validateBBox(bbox) {
47956             if (!bbox) {
47957               throw new Error("bbox is required");
47958             }
47959
47960             if (!Array.isArray(bbox)) {
47961               throw new Error("bbox must be an Array");
47962             }
47963
47964             if (bbox.length !== 4 && bbox.length !== 6) {
47965               throw new Error("bbox must be an Array of 4 or 6 numbers");
47966             }
47967
47968             bbox.forEach(function (num) {
47969               if (!isNumber(num)) {
47970                 throw new Error("bbox must only contain numbers");
47971               }
47972             });
47973           }
47974
47975           exports.validateBBox = validateBBox;
47976           /**
47977            * Validate Id
47978            *
47979            * @private
47980            * @param {string|number} id Id to validate
47981            * @returns {void}
47982            * @throws Error if Id is not valid
47983            * @example
47984            * validateId([-180, -40, 110, 50])
47985            * //=Error
47986            * validateId([-180, -40])
47987            * //=Error
47988            * validateId('Foo')
47989            * //=OK
47990            * validateId(5)
47991            * //=OK
47992            * validateId(null)
47993            * //=Error
47994            * validateId(undefined)
47995            * //=Error
47996            */
47997
47998           function validateId(id) {
47999             if (!id) {
48000               throw new Error("id is required");
48001             }
48002
48003             if (["string", "number"].indexOf(_typeof(id)) === -1) {
48004               throw new Error("id must be a number or a string");
48005             }
48006           }
48007
48008           exports.validateId = validateId; // Deprecated methods
48009
48010           function radians2degrees() {
48011             throw new Error("method has been renamed to `radiansToDegrees`");
48012           }
48013
48014           exports.radians2degrees = radians2degrees;
48015
48016           function degrees2radians() {
48017             throw new Error("method has been renamed to `degreesToRadians`");
48018           }
48019
48020           exports.degrees2radians = degrees2radians;
48021
48022           function distanceToDegrees() {
48023             throw new Error("method has been renamed to `lengthToDegrees`");
48024           }
48025
48026           exports.distanceToDegrees = distanceToDegrees;
48027
48028           function distanceToRadians() {
48029             throw new Error("method has been renamed to `lengthToRadians`");
48030           }
48031
48032           exports.distanceToRadians = distanceToRadians;
48033
48034           function radiansToDistance() {
48035             throw new Error("method has been renamed to `radiansToLength`");
48036           }
48037
48038           exports.radiansToDistance = radiansToDistance;
48039
48040           function bearingToAngle() {
48041             throw new Error("method has been renamed to `bearingToAzimuth`");
48042           }
48043
48044           exports.bearingToAngle = bearingToAngle;
48045
48046           function convertDistance() {
48047             throw new Error("method has been renamed to `convertLength`");
48048           }
48049
48050           exports.convertDistance = convertDistance;
48051         });
48052
48053         var invariant = createCommonjsModule(function (module, exports) {
48054
48055           Object.defineProperty(exports, "__esModule", {
48056             value: true
48057           });
48058           /**
48059            * Unwrap a coordinate from a Point Feature, Geometry or a single coordinate.
48060            *
48061            * @name getCoord
48062            * @param {Array<number>|Geometry<Point>|Feature<Point>} coord GeoJSON Point or an Array of numbers
48063            * @returns {Array<number>} coordinates
48064            * @example
48065            * var pt = turf.point([10, 10]);
48066            *
48067            * var coord = turf.getCoord(pt);
48068            * //= [10, 10]
48069            */
48070
48071           function getCoord(coord) {
48072             if (!coord) {
48073               throw new Error("coord is required");
48074             }
48075
48076             if (!Array.isArray(coord)) {
48077               if (coord.type === "Feature" && coord.geometry !== null && coord.geometry.type === "Point") {
48078                 return coord.geometry.coordinates;
48079               }
48080
48081               if (coord.type === "Point") {
48082                 return coord.coordinates;
48083               }
48084             }
48085
48086             if (Array.isArray(coord) && coord.length >= 2 && !Array.isArray(coord[0]) && !Array.isArray(coord[1])) {
48087               return coord;
48088             }
48089
48090             throw new Error("coord must be GeoJSON Point or an Array of numbers");
48091           }
48092
48093           exports.getCoord = getCoord;
48094           /**
48095            * Unwrap coordinates from a Feature, Geometry Object or an Array
48096            *
48097            * @name getCoords
48098            * @param {Array<any>|Geometry|Feature} coords Feature, Geometry Object or an Array
48099            * @returns {Array<any>} coordinates
48100            * @example
48101            * var poly = turf.polygon([[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]]);
48102            *
48103            * var coords = turf.getCoords(poly);
48104            * //= [[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]]
48105            */
48106
48107           function getCoords(coords) {
48108             if (Array.isArray(coords)) {
48109               return coords;
48110             } // Feature
48111
48112
48113             if (coords.type === "Feature") {
48114               if (coords.geometry !== null) {
48115                 return coords.geometry.coordinates;
48116               }
48117             } else {
48118               // Geometry
48119               if (coords.coordinates) {
48120                 return coords.coordinates;
48121               }
48122             }
48123
48124             throw new Error("coords must be GeoJSON Feature, Geometry Object or an Array");
48125           }
48126
48127           exports.getCoords = getCoords;
48128           /**
48129            * Checks if coordinates contains a number
48130            *
48131            * @name containsNumber
48132            * @param {Array<any>} coordinates GeoJSON Coordinates
48133            * @returns {boolean} true if Array contains a number
48134            */
48135
48136           function containsNumber(coordinates) {
48137             if (coordinates.length > 1 && helpers$1.isNumber(coordinates[0]) && helpers$1.isNumber(coordinates[1])) {
48138               return true;
48139             }
48140
48141             if (Array.isArray(coordinates[0]) && coordinates[0].length) {
48142               return containsNumber(coordinates[0]);
48143             }
48144
48145             throw new Error("coordinates must only contain numbers");
48146           }
48147
48148           exports.containsNumber = containsNumber;
48149           /**
48150            * Enforce expectations about types of GeoJSON objects for Turf.
48151            *
48152            * @name geojsonType
48153            * @param {GeoJSON} value any GeoJSON object
48154            * @param {string} type expected GeoJSON type
48155            * @param {string} name name of calling function
48156            * @throws {Error} if value is not the expected type.
48157            */
48158
48159           function geojsonType(value, type, name) {
48160             if (!type || !name) {
48161               throw new Error("type and name required");
48162             }
48163
48164             if (!value || value.type !== type) {
48165               throw new Error("Invalid input to " + name + ": must be a " + type + ", given " + value.type);
48166             }
48167           }
48168
48169           exports.geojsonType = geojsonType;
48170           /**
48171            * Enforce expectations about types of {@link Feature} inputs for Turf.
48172            * Internally this uses {@link geojsonType} to judge geometry types.
48173            *
48174            * @name featureOf
48175            * @param {Feature} feature a feature with an expected geometry type
48176            * @param {string} type expected GeoJSON type
48177            * @param {string} name name of calling function
48178            * @throws {Error} error if value is not the expected type.
48179            */
48180
48181           function featureOf(feature, type, name) {
48182             if (!feature) {
48183               throw new Error("No feature passed");
48184             }
48185
48186             if (!name) {
48187               throw new Error(".featureOf() requires a name");
48188             }
48189
48190             if (!feature || feature.type !== "Feature" || !feature.geometry) {
48191               throw new Error("Invalid input to " + name + ", Feature with geometry required");
48192             }
48193
48194             if (!feature.geometry || feature.geometry.type !== type) {
48195               throw new Error("Invalid input to " + name + ": must be a " + type + ", given " + feature.geometry.type);
48196             }
48197           }
48198
48199           exports.featureOf = featureOf;
48200           /**
48201            * Enforce expectations about types of {@link FeatureCollection} inputs for Turf.
48202            * Internally this uses {@link geojsonType} to judge geometry types.
48203            *
48204            * @name collectionOf
48205            * @param {FeatureCollection} featureCollection a FeatureCollection for which features will be judged
48206            * @param {string} type expected GeoJSON type
48207            * @param {string} name name of calling function
48208            * @throws {Error} if value is not the expected type.
48209            */
48210
48211           function collectionOf(featureCollection, type, name) {
48212             if (!featureCollection) {
48213               throw new Error("No featureCollection passed");
48214             }
48215
48216             if (!name) {
48217               throw new Error(".collectionOf() requires a name");
48218             }
48219
48220             if (!featureCollection || featureCollection.type !== "FeatureCollection") {
48221               throw new Error("Invalid input to " + name + ", FeatureCollection required");
48222             }
48223
48224             for (var _i = 0, _a = featureCollection.features; _i < _a.length; _i++) {
48225               var feature = _a[_i];
48226
48227               if (!feature || feature.type !== "Feature" || !feature.geometry) {
48228                 throw new Error("Invalid input to " + name + ", Feature with geometry required");
48229               }
48230
48231               if (!feature.geometry || feature.geometry.type !== type) {
48232                 throw new Error("Invalid input to " + name + ": must be a " + type + ", given " + feature.geometry.type);
48233               }
48234             }
48235           }
48236
48237           exports.collectionOf = collectionOf;
48238           /**
48239            * Get Geometry from Feature or Geometry Object
48240            *
48241            * @param {Feature|Geometry} geojson GeoJSON Feature or Geometry Object
48242            * @returns {Geometry|null} GeoJSON Geometry Object
48243            * @throws {Error} if geojson is not a Feature or Geometry Object
48244            * @example
48245            * var point = {
48246            *   "type": "Feature",
48247            *   "properties": {},
48248            *   "geometry": {
48249            *     "type": "Point",
48250            *     "coordinates": [110, 40]
48251            *   }
48252            * }
48253            * var geom = turf.getGeom(point)
48254            * //={"type": "Point", "coordinates": [110, 40]}
48255            */
48256
48257           function getGeom(geojson) {
48258             if (geojson.type === "Feature") {
48259               return geojson.geometry;
48260             }
48261
48262             return geojson;
48263           }
48264
48265           exports.getGeom = getGeom;
48266           /**
48267            * Get GeoJSON object's type, Geometry type is prioritize.
48268            *
48269            * @param {GeoJSON} geojson GeoJSON object
48270            * @param {string} [name="geojson"] name of the variable to display in error message
48271            * @returns {string} GeoJSON type
48272            * @example
48273            * var point = {
48274            *   "type": "Feature",
48275            *   "properties": {},
48276            *   "geometry": {
48277            *     "type": "Point",
48278            *     "coordinates": [110, 40]
48279            *   }
48280            * }
48281            * var geom = turf.getType(point)
48282            * //="Point"
48283            */
48284
48285           function getType(geojson, name) {
48286             if (geojson.type === "FeatureCollection") {
48287               return "FeatureCollection";
48288             }
48289
48290             if (geojson.type === "GeometryCollection") {
48291               return "GeometryCollection";
48292             }
48293
48294             if (geojson.type === "Feature" && geojson.geometry !== null) {
48295               return geojson.geometry.type;
48296             }
48297
48298             return geojson.type;
48299           }
48300
48301           exports.getType = getType;
48302         });
48303
48304         var lineclip_1 = lineclip;
48305         var _default = lineclip;
48306         lineclip.polyline = lineclip;
48307         lineclip.polygon = polygonclip; // Cohen-Sutherland line clippign algorithm, adapted to efficiently
48308         // handle polylines rather than just segments
48309
48310         function lineclip(points, bbox, result) {
48311           var len = points.length,
48312               codeA = bitCode(points[0], bbox),
48313               part = [],
48314               i,
48315               a,
48316               b,
48317               codeB,
48318               lastCode;
48319           if (!result) result = [];
48320
48321           for (i = 1; i < len; i++) {
48322             a = points[i - 1];
48323             b = points[i];
48324             codeB = lastCode = bitCode(b, bbox);
48325
48326             while (true) {
48327               if (!(codeA | codeB)) {
48328                 // accept
48329                 part.push(a);
48330
48331                 if (codeB !== lastCode) {
48332                   // segment went outside
48333                   part.push(b);
48334
48335                   if (i < len - 1) {
48336                     // start a new line
48337                     result.push(part);
48338                     part = [];
48339                   }
48340                 } else if (i === len - 1) {
48341                   part.push(b);
48342                 }
48343
48344                 break;
48345               } else if (codeA & codeB) {
48346                 // trivial reject
48347                 break;
48348               } else if (codeA) {
48349                 // a outside, intersect with clip edge
48350                 a = intersect(a, b, codeA, bbox);
48351                 codeA = bitCode(a, bbox);
48352               } else {
48353                 // b outside
48354                 b = intersect(a, b, codeB, bbox);
48355                 codeB = bitCode(b, bbox);
48356               }
48357             }
48358
48359             codeA = lastCode;
48360           }
48361
48362           if (part.length) result.push(part);
48363           return result;
48364         } // Sutherland-Hodgeman polygon clipping algorithm
48365
48366
48367         function polygonclip(points, bbox) {
48368           var result, edge, prev, prevInside, i, p, inside; // clip against each side of the clip rectangle
48369
48370           for (edge = 1; edge <= 8; edge *= 2) {
48371             result = [];
48372             prev = points[points.length - 1];
48373             prevInside = !(bitCode(prev, bbox) & edge);
48374
48375             for (i = 0; i < points.length; i++) {
48376               p = points[i];
48377               inside = !(bitCode(p, bbox) & edge); // if segment goes through the clip window, add an intersection
48378
48379               if (inside !== prevInside) result.push(intersect(prev, p, edge, bbox));
48380               if (inside) result.push(p); // add a point if it's inside
48381
48382               prev = p;
48383               prevInside = inside;
48384             }
48385
48386             points = result;
48387             if (!points.length) break;
48388           }
48389
48390           return result;
48391         } // intersect a segment against one of the 4 lines that make up the bbox
48392
48393
48394         function intersect(a, b, edge, bbox) {
48395           return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] : // top
48396           edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] : // bottom
48397           edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] : // right
48398           edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] : // left
48399           null;
48400         } // bit code reflects the point position relative to the bbox:
48401         //         left  mid  right
48402         //    top  1001  1000  1010
48403         //    mid  0001  0000  0010
48404         // bottom  0101  0100  0110
48405
48406
48407         function bitCode(p, bbox) {
48408           var code = 0;
48409           if (p[0] < bbox[0]) code |= 1; // left
48410           else if (p[0] > bbox[2]) code |= 2; // right
48411
48412           if (p[1] < bbox[1]) code |= 4; // bottom
48413           else if (p[1] > bbox[3]) code |= 8; // top
48414
48415           return code;
48416         }
48417         lineclip_1["default"] = _default;
48418
48419         var bboxClip_1 = createCommonjsModule(function (module, exports) {
48420
48421           var __importStar = commonjsGlobal && commonjsGlobal.__importStar || function (mod) {
48422             if (mod && mod.__esModule) return mod;
48423             var result = {};
48424             if (mod != null) for (var k in mod) {
48425               if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
48426             }
48427             result["default"] = mod;
48428             return result;
48429           };
48430
48431           Object.defineProperty(exports, "__esModule", {
48432             value: true
48433           });
48434
48435           var lineclip = __importStar(lineclip_1);
48436           /**
48437            * Takes a {@link Feature} and a bbox and clips the feature to the bbox using
48438            * [lineclip](https://github.com/mapbox/lineclip).
48439            * May result in degenerate edges when clipping Polygons.
48440            *
48441            * @name bboxClip
48442            * @param {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} feature feature to clip to the bbox
48443            * @param {BBox} bbox extent in [minX, minY, maxX, maxY] order
48444            * @returns {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} clipped Feature
48445            * @example
48446            * var bbox = [0, 0, 10, 10];
48447            * var poly = turf.polygon([[[2, 2], [8, 4], [12, 8], [3, 7], [2, 2]]]);
48448            *
48449            * var clipped = turf.bboxClip(poly, bbox);
48450            *
48451            * //addToMap
48452            * var addToMap = [bbox, poly, clipped]
48453            */
48454
48455
48456           function bboxClip(feature, bbox) {
48457             var geom = invariant.getGeom(feature);
48458             var type = geom.type;
48459             var properties = feature.type === "Feature" ? feature.properties : {};
48460             var coords = geom.coordinates;
48461
48462             switch (type) {
48463               case "LineString":
48464               case "MultiLineString":
48465                 var lines_1 = [];
48466
48467                 if (type === "LineString") {
48468                   coords = [coords];
48469                 }
48470
48471                 coords.forEach(function (line) {
48472                   lineclip.polyline(line, bbox, lines_1);
48473                 });
48474
48475                 if (lines_1.length === 1) {
48476                   return helpers$1.lineString(lines_1[0], properties);
48477                 }
48478
48479                 return helpers$1.multiLineString(lines_1, properties);
48480
48481               case "Polygon":
48482                 return helpers$1.polygon(clipPolygon(coords, bbox), properties);
48483
48484               case "MultiPolygon":
48485                 return helpers$1.multiPolygon(coords.map(function (poly) {
48486                   return clipPolygon(poly, bbox);
48487                 }), properties);
48488
48489               default:
48490                 throw new Error("geometry " + type + " not supported");
48491             }
48492           }
48493
48494           exports["default"] = bboxClip;
48495
48496           function clipPolygon(rings, bbox) {
48497             var outRings = [];
48498
48499             for (var _i = 0, rings_1 = rings; _i < rings_1.length; _i++) {
48500               var ring = rings_1[_i];
48501               var clipped = lineclip.polygon(ring, bbox);
48502
48503               if (clipped.length > 0) {
48504                 if (clipped[0][0] !== clipped[clipped.length - 1][0] || clipped[0][1] !== clipped[clipped.length - 1][1]) {
48505                   clipped.push(clipped[0]);
48506                 }
48507
48508                 if (clipped.length >= 4) {
48509                   outRings.push(clipped);
48510                 }
48511               }
48512             }
48513
48514             return outRings;
48515           }
48516         });
48517         var turf_bboxClip = /*@__PURE__*/getDefaultExportFromCjs(bboxClip_1);
48518
48519         var fastJsonStableStringify = function fastJsonStableStringify(data, opts) {
48520           if (!opts) opts = {};
48521           if (typeof opts === 'function') opts = {
48522             cmp: opts
48523           };
48524           var cycles = typeof opts.cycles === 'boolean' ? opts.cycles : false;
48525
48526           var cmp = opts.cmp && function (f) {
48527             return function (node) {
48528               return function (a, b) {
48529                 var aobj = {
48530                   key: a,
48531                   value: node[a]
48532                 };
48533                 var bobj = {
48534                   key: b,
48535                   value: node[b]
48536                 };
48537                 return f(aobj, bobj);
48538               };
48539             };
48540           }(opts.cmp);
48541
48542           var seen = [];
48543           return function stringify(node) {
48544             if (node && node.toJSON && typeof node.toJSON === 'function') {
48545               node = node.toJSON();
48546             }
48547
48548             if (node === undefined) return;
48549             if (typeof node == 'number') return isFinite(node) ? '' + node : 'null';
48550             if (_typeof(node) !== 'object') return JSON.stringify(node);
48551             var i, out;
48552
48553             if (Array.isArray(node)) {
48554               out = '[';
48555
48556               for (i = 0; i < node.length; i++) {
48557                 if (i) out += ',';
48558                 out += stringify(node[i]) || 'null';
48559               }
48560
48561               return out + ']';
48562             }
48563
48564             if (node === null) return 'null';
48565
48566             if (seen.indexOf(node) !== -1) {
48567               if (cycles) return JSON.stringify('__cycle__');
48568               throw new TypeError('Converting circular structure to JSON');
48569             }
48570
48571             var seenIndex = seen.push(node) - 1;
48572             var keys = Object.keys(node).sort(cmp && cmp(node));
48573             out = '';
48574
48575             for (i = 0; i < keys.length; i++) {
48576               var key = keys[i];
48577               var value = stringify(node[key]);
48578               if (!value) continue;
48579               if (out) out += ',';
48580               out += JSON.stringify(key) + ':' + value;
48581             }
48582
48583             seen.splice(seenIndex, 1);
48584             return '{' + out + '}';
48585           }(data);
48586         };
48587
48588         function DEFAULT_COMPARE(a, b) {
48589           return a > b ? 1 : a < b ? -1 : 0;
48590         }
48591
48592         var SplayTree = /*#__PURE__*/function () {
48593           function SplayTree() {
48594             var compare = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_COMPARE;
48595             var noDuplicates = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
48596
48597             _classCallCheck(this, SplayTree);
48598
48599             this._compare = compare;
48600             this._root = null;
48601             this._size = 0;
48602             this._noDuplicates = !!noDuplicates;
48603           }
48604
48605           _createClass(SplayTree, [{
48606             key: "rotateLeft",
48607             value: function rotateLeft(x) {
48608               var y = x.right;
48609
48610               if (y) {
48611                 x.right = y.left;
48612                 if (y.left) y.left.parent = x;
48613                 y.parent = x.parent;
48614               }
48615
48616               if (!x.parent) this._root = y;else if (x === x.parent.left) x.parent.left = y;else x.parent.right = y;
48617               if (y) y.left = x;
48618               x.parent = y;
48619             }
48620           }, {
48621             key: "rotateRight",
48622             value: function rotateRight(x) {
48623               var y = x.left;
48624
48625               if (y) {
48626                 x.left = y.right;
48627                 if (y.right) y.right.parent = x;
48628                 y.parent = x.parent;
48629               }
48630
48631               if (!x.parent) this._root = y;else if (x === x.parent.left) x.parent.left = y;else x.parent.right = y;
48632               if (y) y.right = x;
48633               x.parent = y;
48634             }
48635           }, {
48636             key: "_splay",
48637             value: function _splay(x) {
48638               while (x.parent) {
48639                 var p = x.parent;
48640
48641                 if (!p.parent) {
48642                   if (p.left === x) this.rotateRight(p);else this.rotateLeft(p);
48643                 } else if (p.left === x && p.parent.left === p) {
48644                   this.rotateRight(p.parent);
48645                   this.rotateRight(p);
48646                 } else if (p.right === x && p.parent.right === p) {
48647                   this.rotateLeft(p.parent);
48648                   this.rotateLeft(p);
48649                 } else if (p.left === x && p.parent.right === p) {
48650                   this.rotateRight(p);
48651                   this.rotateLeft(p);
48652                 } else {
48653                   this.rotateLeft(p);
48654                   this.rotateRight(p);
48655                 }
48656               }
48657             }
48658           }, {
48659             key: "splay",
48660             value: function splay(x) {
48661               var p, gp, ggp, l, r;
48662
48663               while (x.parent) {
48664                 p = x.parent;
48665                 gp = p.parent;
48666
48667                 if (gp && gp.parent) {
48668                   ggp = gp.parent;
48669                   if (ggp.left === gp) ggp.left = x;else ggp.right = x;
48670                   x.parent = ggp;
48671                 } else {
48672                   x.parent = null;
48673                   this._root = x;
48674                 }
48675
48676                 l = x.left;
48677                 r = x.right;
48678
48679                 if (x === p.left) {
48680                   // left
48681                   if (gp) {
48682                     if (gp.left === p) {
48683                       /* zig-zig */
48684                       if (p.right) {
48685                         gp.left = p.right;
48686                         gp.left.parent = gp;
48687                       } else gp.left = null;
48688
48689                       p.right = gp;
48690                       gp.parent = p;
48691                     } else {
48692                       /* zig-zag */
48693                       if (l) {
48694                         gp.right = l;
48695                         l.parent = gp;
48696                       } else gp.right = null;
48697
48698                       x.left = gp;
48699                       gp.parent = x;
48700                     }
48701                   }
48702
48703                   if (r) {
48704                     p.left = r;
48705                     r.parent = p;
48706                   } else p.left = null;
48707
48708                   x.right = p;
48709                   p.parent = x;
48710                 } else {
48711                   // right
48712                   if (gp) {
48713                     if (gp.right === p) {
48714                       /* zig-zig */
48715                       if (p.left) {
48716                         gp.right = p.left;
48717                         gp.right.parent = gp;
48718                       } else gp.right = null;
48719
48720                       p.left = gp;
48721                       gp.parent = p;
48722                     } else {
48723                       /* zig-zag */
48724                       if (r) {
48725                         gp.left = r;
48726                         r.parent = gp;
48727                       } else gp.left = null;
48728
48729                       x.right = gp;
48730                       gp.parent = x;
48731                     }
48732                   }
48733
48734                   if (l) {
48735                     p.right = l;
48736                     l.parent = p;
48737                   } else p.right = null;
48738
48739                   x.left = p;
48740                   p.parent = x;
48741                 }
48742               }
48743             }
48744           }, {
48745             key: "replace",
48746             value: function replace(u, v) {
48747               if (!u.parent) this._root = v;else if (u === u.parent.left) u.parent.left = v;else u.parent.right = v;
48748               if (v) v.parent = u.parent;
48749             }
48750           }, {
48751             key: "minNode",
48752             value: function minNode() {
48753               var u = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._root;
48754               if (u) while (u.left) {
48755                 u = u.left;
48756               }
48757               return u;
48758             }
48759           }, {
48760             key: "maxNode",
48761             value: function maxNode() {
48762               var u = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._root;
48763               if (u) while (u.right) {
48764                 u = u.right;
48765               }
48766               return u;
48767             }
48768           }, {
48769             key: "insert",
48770             value: function insert(key, data) {
48771               var z = this._root;
48772               var p = null;
48773               var comp = this._compare;
48774               var cmp;
48775
48776               if (this._noDuplicates) {
48777                 while (z) {
48778                   p = z;
48779                   cmp = comp(z.key, key);
48780                   if (cmp === 0) return;else if (comp(z.key, key) < 0) z = z.right;else z = z.left;
48781                 }
48782               } else {
48783                 while (z) {
48784                   p = z;
48785                   if (comp(z.key, key) < 0) z = z.right;else z = z.left;
48786                 }
48787               }
48788
48789               z = {
48790                 key: key,
48791                 data: data,
48792                 left: null,
48793                 right: null,
48794                 parent: p
48795               };
48796               if (!p) this._root = z;else if (comp(p.key, z.key) < 0) p.right = z;else p.left = z;
48797               this.splay(z);
48798               this._size++;
48799               return z;
48800             }
48801           }, {
48802             key: "find",
48803             value: function find(key) {
48804               var z = this._root;
48805               var comp = this._compare;
48806
48807               while (z) {
48808                 var cmp = comp(z.key, key);
48809                 if (cmp < 0) z = z.right;else if (cmp > 0) z = z.left;else return z;
48810               }
48811
48812               return null;
48813             }
48814             /**
48815              * Whether the tree contains a node with the given key
48816              * @param  {Key} key
48817              * @return {boolean} true/false
48818              */
48819
48820           }, {
48821             key: "contains",
48822             value: function contains(key) {
48823               var node = this._root;
48824               var comparator = this._compare;
48825
48826               while (node) {
48827                 var cmp = comparator(key, node.key);
48828                 if (cmp === 0) return true;else if (cmp < 0) node = node.left;else node = node.right;
48829               }
48830
48831               return false;
48832             }
48833           }, {
48834             key: "remove",
48835             value: function remove(key) {
48836               var z = this.find(key);
48837               if (!z) return false;
48838               this.splay(z);
48839               if (!z.left) this.replace(z, z.right);else if (!z.right) this.replace(z, z.left);else {
48840                 var y = this.minNode(z.right);
48841
48842                 if (y.parent !== z) {
48843                   this.replace(y, y.right);
48844                   y.right = z.right;
48845                   y.right.parent = y;
48846                 }
48847
48848                 this.replace(z, y);
48849                 y.left = z.left;
48850                 y.left.parent = y;
48851               }
48852               this._size--;
48853               return true;
48854             }
48855           }, {
48856             key: "removeNode",
48857             value: function removeNode(z) {
48858               if (!z) return false;
48859               this.splay(z);
48860               if (!z.left) this.replace(z, z.right);else if (!z.right) this.replace(z, z.left);else {
48861                 var y = this.minNode(z.right);
48862
48863                 if (y.parent !== z) {
48864                   this.replace(y, y.right);
48865                   y.right = z.right;
48866                   y.right.parent = y;
48867                 }
48868
48869                 this.replace(z, y);
48870                 y.left = z.left;
48871                 y.left.parent = y;
48872               }
48873               this._size--;
48874               return true;
48875             }
48876           }, {
48877             key: "erase",
48878             value: function erase(key) {
48879               var z = this.find(key);
48880               if (!z) return;
48881               this.splay(z);
48882               var s = z.left;
48883               var t = z.right;
48884               var sMax = null;
48885
48886               if (s) {
48887                 s.parent = null;
48888                 sMax = this.maxNode(s);
48889                 this.splay(sMax);
48890                 this._root = sMax;
48891               }
48892
48893               if (t) {
48894                 if (s) sMax.right = t;else this._root = t;
48895                 t.parent = sMax;
48896               }
48897
48898               this._size--;
48899             }
48900             /**
48901              * Removes and returns the node with smallest key
48902              * @return {?Node}
48903              */
48904
48905           }, {
48906             key: "pop",
48907             value: function pop() {
48908               var node = this._root,
48909                   returnValue = null;
48910
48911               if (node) {
48912                 while (node.left) {
48913                   node = node.left;
48914                 }
48915
48916                 returnValue = {
48917                   key: node.key,
48918                   data: node.data
48919                 };
48920                 this.remove(node.key);
48921               }
48922
48923               return returnValue;
48924             }
48925             /* eslint-disable class-methods-use-this */
48926
48927             /**
48928              * Successor node
48929              * @param  {Node} node
48930              * @return {?Node}
48931              */
48932
48933           }, {
48934             key: "next",
48935             value: function next(node) {
48936               var successor = node;
48937
48938               if (successor) {
48939                 if (successor.right) {
48940                   successor = successor.right;
48941
48942                   while (successor && successor.left) {
48943                     successor = successor.left;
48944                   }
48945                 } else {
48946                   successor = node.parent;
48947
48948                   while (successor && successor.right === node) {
48949                     node = successor;
48950                     successor = successor.parent;
48951                   }
48952                 }
48953               }
48954
48955               return successor;
48956             }
48957             /**
48958              * Predecessor node
48959              * @param  {Node} node
48960              * @return {?Node}
48961              */
48962
48963           }, {
48964             key: "prev",
48965             value: function prev(node) {
48966               var predecessor = node;
48967
48968               if (predecessor) {
48969                 if (predecessor.left) {
48970                   predecessor = predecessor.left;
48971
48972                   while (predecessor && predecessor.right) {
48973                     predecessor = predecessor.right;
48974                   }
48975                 } else {
48976                   predecessor = node.parent;
48977
48978                   while (predecessor && predecessor.left === node) {
48979                     node = predecessor;
48980                     predecessor = predecessor.parent;
48981                   }
48982                 }
48983               }
48984
48985               return predecessor;
48986             }
48987             /* eslint-enable class-methods-use-this */
48988
48989             /**
48990              * @param  {forEachCallback} callback
48991              * @return {SplayTree}
48992              */
48993
48994           }, {
48995             key: "forEach",
48996             value: function forEach(callback) {
48997               var current = this._root;
48998               var s = [],
48999                   done = false,
49000                   i = 0;
49001
49002               while (!done) {
49003                 // Reach the left most Node of the current Node
49004                 if (current) {
49005                   // Place pointer to a tree node on the stack
49006                   // before traversing the node's left subtree
49007                   s.push(current);
49008                   current = current.left;
49009                 } else {
49010                   // BackTrack from the empty subtree and visit the Node
49011                   // at the top of the stack; however, if the stack is
49012                   // empty you are done
49013                   if (s.length > 0) {
49014                     current = s.pop();
49015                     callback(current, i++); // We have visited the node and its left
49016                     // subtree. Now, it's right subtree's turn
49017
49018                     current = current.right;
49019                   } else done = true;
49020                 }
49021               }
49022
49023               return this;
49024             }
49025             /**
49026              * Walk key range from `low` to `high`. Stops if `fn` returns a value.
49027              * @param  {Key}      low
49028              * @param  {Key}      high
49029              * @param  {Function} fn
49030              * @param  {*?}       ctx
49031              * @return {SplayTree}
49032              */
49033
49034           }, {
49035             key: "range",
49036             value: function range(low, high, fn, ctx) {
49037               var Q = [];
49038               var compare = this._compare;
49039               var node = this._root,
49040                   cmp;
49041
49042               while (Q.length !== 0 || node) {
49043                 if (node) {
49044                   Q.push(node);
49045                   node = node.left;
49046                 } else {
49047                   node = Q.pop();
49048                   cmp = compare(node.key, high);
49049
49050                   if (cmp > 0) {
49051                     break;
49052                   } else if (compare(node.key, low) >= 0) {
49053                     if (fn.call(ctx, node)) return this; // stop if smth is returned
49054                   }
49055
49056                   node = node.right;
49057                 }
49058               }
49059
49060               return this;
49061             }
49062             /**
49063              * Returns all keys in order
49064              * @return {Array<Key>}
49065              */
49066
49067           }, {
49068             key: "keys",
49069             value: function keys() {
49070               var current = this._root;
49071               var s = [],
49072                   r = [],
49073                   done = false;
49074
49075               while (!done) {
49076                 if (current) {
49077                   s.push(current);
49078                   current = current.left;
49079                 } else {
49080                   if (s.length > 0) {
49081                     current = s.pop();
49082                     r.push(current.key);
49083                     current = current.right;
49084                   } else done = true;
49085                 }
49086               }
49087
49088               return r;
49089             }
49090             /**
49091              * Returns `data` fields of all nodes in order.
49092              * @return {Array<Value>}
49093              */
49094
49095           }, {
49096             key: "values",
49097             value: function values() {
49098               var current = this._root;
49099               var s = [],
49100                   r = [],
49101                   done = false;
49102
49103               while (!done) {
49104                 if (current) {
49105                   s.push(current);
49106                   current = current.left;
49107                 } else {
49108                   if (s.length > 0) {
49109                     current = s.pop();
49110                     r.push(current.data);
49111                     current = current.right;
49112                   } else done = true;
49113                 }
49114               }
49115
49116               return r;
49117             }
49118             /**
49119              * Returns node at given index
49120              * @param  {number} index
49121              * @return {?Node}
49122              */
49123
49124           }, {
49125             key: "at",
49126             value: function at(index) {
49127               // removed after a consideration, more misleading than useful
49128               // index = index % this.size;
49129               // if (index < 0) index = this.size - index;
49130               var current = this._root;
49131               var s = [],
49132                   done = false,
49133                   i = 0;
49134
49135               while (!done) {
49136                 if (current) {
49137                   s.push(current);
49138                   current = current.left;
49139                 } else {
49140                   if (s.length > 0) {
49141                     current = s.pop();
49142                     if (i === index) return current;
49143                     i++;
49144                     current = current.right;
49145                   } else done = true;
49146                 }
49147               }
49148
49149               return null;
49150             }
49151             /**
49152              * Bulk-load items. Both array have to be same size
49153              * @param  {Array<Key>}    keys
49154              * @param  {Array<Value>}  [values]
49155              * @param  {Boolean}       [presort=false] Pre-sort keys and values, using
49156              *                                         tree's comparator. Sorting is done
49157              *                                         in-place
49158              * @return {AVLTree}
49159              */
49160
49161           }, {
49162             key: "load",
49163             value: function load() {
49164               var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
49165               var values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
49166               var presort = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
49167               if (this._size !== 0) throw new Error('bulk-load: tree is not empty');
49168               var size = keys.length;
49169               if (presort) sort(keys, values, 0, size - 1, this._compare);
49170               this._root = loadRecursive(null, keys, values, 0, size);
49171               this._size = size;
49172               return this;
49173             }
49174           }, {
49175             key: "min",
49176             value: function min() {
49177               var node = this.minNode(this._root);
49178               if (node) return node.key;else return null;
49179             }
49180           }, {
49181             key: "max",
49182             value: function max() {
49183               var node = this.maxNode(this._root);
49184               if (node) return node.key;else return null;
49185             }
49186           }, {
49187             key: "isEmpty",
49188             value: function isEmpty() {
49189               return this._root === null;
49190             }
49191           }, {
49192             key: "size",
49193             get: function get() {
49194               return this._size;
49195             }
49196             /**
49197              * Create a tree and load it with items
49198              * @param  {Array<Key>}          keys
49199              * @param  {Array<Value>?}        [values]
49200               * @param  {Function?}            [comparator]
49201              * @param  {Boolean?}             [presort=false] Pre-sort keys and values, using
49202              *                                               tree's comparator. Sorting is done
49203              *                                               in-place
49204              * @param  {Boolean?}             [noDuplicates=false]   Allow duplicates
49205              * @return {SplayTree}
49206              */
49207
49208           }], [{
49209             key: "createTree",
49210             value: function createTree(keys, values, comparator, presort, noDuplicates) {
49211               return new SplayTree(comparator, noDuplicates).load(keys, values, presort);
49212             }
49213           }]);
49214
49215           return SplayTree;
49216         }();
49217
49218         function loadRecursive(parent, keys, values, start, end) {
49219           var size = end - start;
49220
49221           if (size > 0) {
49222             var middle = start + Math.floor(size / 2);
49223             var key = keys[middle];
49224             var data = values[middle];
49225             var node = {
49226               key: key,
49227               data: data,
49228               parent: parent
49229             };
49230             node.left = loadRecursive(node, keys, values, start, middle);
49231             node.right = loadRecursive(node, keys, values, middle + 1, end);
49232             return node;
49233           }
49234
49235           return null;
49236         }
49237
49238         function sort(keys, values, left, right, compare) {
49239           if (left >= right) return;
49240           var pivot = keys[left + right >> 1];
49241           var i = left - 1;
49242           var j = right + 1;
49243
49244           while (true) {
49245             do {
49246               i++;
49247             } while (compare(keys[i], pivot) < 0);
49248
49249             do {
49250               j--;
49251             } while (compare(keys[j], pivot) > 0);
49252
49253             if (i >= j) break;
49254             var tmp = keys[i];
49255             keys[i] = keys[j];
49256             keys[j] = tmp;
49257             tmp = values[i];
49258             values[i] = values[j];
49259             values[j] = tmp;
49260           }
49261
49262           sort(keys, values, left, j, compare);
49263           sort(keys, values, j + 1, right, compare);
49264         }
49265
49266         var NORMAL = 0;
49267         var NON_CONTRIBUTING = 1;
49268         var SAME_TRANSITION = 2;
49269         var DIFFERENT_TRANSITION = 3;
49270
49271         var INTERSECTION = 0;
49272         var UNION = 1;
49273         var DIFFERENCE = 2;
49274         var XOR = 3;
49275
49276         /**
49277          * @param  {SweepEvent} event
49278          * @param  {SweepEvent} prev
49279          * @param  {Operation} operation
49280          */
49281
49282         function computeFields(event, prev, operation) {
49283           // compute inOut and otherInOut fields
49284           if (prev === null) {
49285             event.inOut = false;
49286             event.otherInOut = true; // previous line segment in sweepline belongs to the same polygon
49287           } else {
49288             if (event.isSubject === prev.isSubject) {
49289               event.inOut = !prev.inOut;
49290               event.otherInOut = prev.otherInOut; // previous line segment in sweepline belongs to the clipping polygon
49291             } else {
49292               event.inOut = !prev.otherInOut;
49293               event.otherInOut = prev.isVertical() ? !prev.inOut : prev.inOut;
49294             } // compute prevInResult field
49295
49296
49297             if (prev) {
49298               event.prevInResult = !inResult(prev, operation) || prev.isVertical() ? prev.prevInResult : prev;
49299             }
49300           } // check if the line segment belongs to the Boolean operation
49301
49302
49303           var isInResult = inResult(event, operation);
49304
49305           if (isInResult) {
49306             event.resultTransition = determineResultTransition(event, operation);
49307           } else {
49308             event.resultTransition = 0;
49309           }
49310         }
49311         /* eslint-disable indent */
49312
49313         function inResult(event, operation) {
49314           switch (event.type) {
49315             case NORMAL:
49316               switch (operation) {
49317                 case INTERSECTION:
49318                   return !event.otherInOut;
49319
49320                 case UNION:
49321                   return event.otherInOut;
49322
49323                 case DIFFERENCE:
49324                   // return (event.isSubject && !event.otherInOut) ||
49325                   //         (!event.isSubject && event.otherInOut);
49326                   return event.isSubject && event.otherInOut || !event.isSubject && !event.otherInOut;
49327
49328                 case XOR:
49329                   return true;
49330               }
49331
49332               break;
49333
49334             case SAME_TRANSITION:
49335               return operation === INTERSECTION || operation === UNION;
49336
49337             case DIFFERENT_TRANSITION:
49338               return operation === DIFFERENCE;
49339
49340             case NON_CONTRIBUTING:
49341               return false;
49342           }
49343
49344           return false;
49345         }
49346         /* eslint-enable indent */
49347
49348
49349         function determineResultTransition(event, operation) {
49350           var thisIn = !event.inOut;
49351           var thatIn = !event.otherInOut;
49352           var isIn;
49353
49354           switch (operation) {
49355             case INTERSECTION:
49356               isIn = thisIn && thatIn;
49357               break;
49358
49359             case UNION:
49360               isIn = thisIn || thatIn;
49361               break;
49362
49363             case XOR:
49364               isIn = thisIn ^ thatIn;
49365               break;
49366
49367             case DIFFERENCE:
49368               if (event.isSubject) {
49369                 isIn = thisIn && !thatIn;
49370               } else {
49371                 isIn = thatIn && !thisIn;
49372               }
49373
49374               break;
49375           }
49376
49377           return isIn ? +1 : -1;
49378         }
49379
49380         var SweepEvent = /*#__PURE__*/function () {
49381           /**
49382            * Sweepline event
49383            *
49384            * @class {SweepEvent}
49385            * @param {Array.<Number>}  point
49386            * @param {Boolean}         left
49387            * @param {SweepEvent=}     otherEvent
49388            * @param {Boolean}         isSubject
49389            * @param {Number}          edgeType
49390            */
49391           function SweepEvent(point, left, otherEvent, isSubject, edgeType) {
49392             _classCallCheck(this, SweepEvent);
49393
49394             /**
49395              * Is left endpoint?
49396              * @type {Boolean}
49397              */
49398             this.left = left;
49399             /**
49400              * @type {Array.<Number>}
49401              */
49402
49403             this.point = point;
49404             /**
49405              * Other edge reference
49406              * @type {SweepEvent}
49407              */
49408
49409             this.otherEvent = otherEvent;
49410             /**
49411              * Belongs to source or clipping polygon
49412              * @type {Boolean}
49413              */
49414
49415             this.isSubject = isSubject;
49416             /**
49417              * Edge contribution type
49418              * @type {Number}
49419              */
49420
49421             this.type = edgeType || NORMAL;
49422             /**
49423              * In-out transition for the sweepline crossing polygon
49424              * @type {Boolean}
49425              */
49426
49427             this.inOut = false;
49428             /**
49429              * @type {Boolean}
49430              */
49431
49432             this.otherInOut = false;
49433             /**
49434              * Previous event in result?
49435              * @type {SweepEvent}
49436              */
49437
49438             this.prevInResult = null;
49439             /**
49440              * Type of result transition (0 = not in result, +1 = out-in, -1, in-out)
49441              * @type {Number}
49442              */
49443
49444             this.resultTransition = 0; // connection step
49445
49446             /**
49447              * @type {Number}
49448              */
49449
49450             this.otherPos = -1;
49451             /**
49452              * @type {Number}
49453              */
49454
49455             this.outputContourId = -1;
49456             this.isExteriorRing = true; // TODO: Looks unused, remove?
49457           }
49458           /**
49459            * @param  {Array.<Number>}  p
49460            * @return {Boolean}
49461            */
49462
49463
49464           _createClass(SweepEvent, [{
49465             key: "isBelow",
49466             value: function isBelow(p) {
49467               var p0 = this.point,
49468                   p1 = this.otherEvent.point;
49469               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 :
49470               : (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;
49471             }
49472             /**
49473              * @param  {Array.<Number>}  p
49474              * @return {Boolean}
49475              */
49476
49477           }, {
49478             key: "isAbove",
49479             value: function isAbove(p) {
49480               return !this.isBelow(p);
49481             }
49482             /**
49483              * @return {Boolean}
49484              */
49485
49486           }, {
49487             key: "isVertical",
49488             value: function isVertical() {
49489               return this.point[0] === this.otherEvent.point[0];
49490             }
49491             /**
49492              * Does event belong to result?
49493              * @return {Boolean}
49494              */
49495
49496           }, {
49497             key: "clone",
49498             value: function clone() {
49499               var copy = new SweepEvent(this.point, this.left, this.otherEvent, this.isSubject, this.type);
49500               copy.contourId = this.contourId;
49501               copy.resultTransition = this.resultTransition;
49502               copy.prevInResult = this.prevInResult;
49503               copy.isExteriorRing = this.isExteriorRing;
49504               copy.inOut = this.inOut;
49505               copy.otherInOut = this.otherInOut;
49506               return copy;
49507             }
49508           }, {
49509             key: "inResult",
49510             get: function get() {
49511               return this.resultTransition !== 0;
49512             }
49513           }]);
49514
49515           return SweepEvent;
49516         }();
49517
49518         function equals(p1, p2) {
49519           if (p1[0] === p2[0]) {
49520             if (p1[1] === p2[1]) {
49521               return true;
49522             } else {
49523               return false;
49524             }
49525           }
49526
49527           return false;
49528         } // const EPSILON = 1e-9;
49529         // const abs = Math.abs;
49530         // TODO https://github.com/w8r/martinez/issues/6#issuecomment-262847164
49531         // Precision problem.
49532         //
49533         // module.exports = function equals(p1, p2) {
49534         //   return abs(p1[0] - p2[0]) <= EPSILON && abs(p1[1] - p2[1]) <= EPSILON;
49535         // };
49536
49537         var epsilon$1 = 1.1102230246251565e-16;
49538         var splitter = 134217729;
49539         var resulterrbound = (3 + 8 * epsilon$1) * epsilon$1; // fast_expansion_sum_zeroelim routine from oritinal code
49540
49541         function sum(elen, e, flen, f, h) {
49542           var Q, Qnew, hh, bvirt;
49543           var enow = e[0];
49544           var fnow = f[0];
49545           var eindex = 0;
49546           var findex = 0;
49547
49548           if (fnow > enow === fnow > -enow) {
49549             Q = enow;
49550             enow = e[++eindex];
49551           } else {
49552             Q = fnow;
49553             fnow = f[++findex];
49554           }
49555
49556           var hindex = 0;
49557
49558           if (eindex < elen && findex < flen) {
49559             if (fnow > enow === fnow > -enow) {
49560               Qnew = enow + Q;
49561               hh = Q - (Qnew - enow);
49562               enow = e[++eindex];
49563             } else {
49564               Qnew = fnow + Q;
49565               hh = Q - (Qnew - fnow);
49566               fnow = f[++findex];
49567             }
49568
49569             Q = Qnew;
49570
49571             if (hh !== 0) {
49572               h[hindex++] = hh;
49573             }
49574
49575             while (eindex < elen && findex < flen) {
49576               if (fnow > enow === fnow > -enow) {
49577                 Qnew = Q + enow;
49578                 bvirt = Qnew - Q;
49579                 hh = Q - (Qnew - bvirt) + (enow - bvirt);
49580                 enow = e[++eindex];
49581               } else {
49582                 Qnew = Q + fnow;
49583                 bvirt = Qnew - Q;
49584                 hh = Q - (Qnew - bvirt) + (fnow - bvirt);
49585                 fnow = f[++findex];
49586               }
49587
49588               Q = Qnew;
49589
49590               if (hh !== 0) {
49591                 h[hindex++] = hh;
49592               }
49593             }
49594           }
49595
49596           while (eindex < elen) {
49597             Qnew = Q + enow;
49598             bvirt = Qnew - Q;
49599             hh = Q - (Qnew - bvirt) + (enow - bvirt);
49600             enow = e[++eindex];
49601             Q = Qnew;
49602
49603             if (hh !== 0) {
49604               h[hindex++] = hh;
49605             }
49606           }
49607
49608           while (findex < flen) {
49609             Qnew = Q + fnow;
49610             bvirt = Qnew - Q;
49611             hh = Q - (Qnew - bvirt) + (fnow - bvirt);
49612             fnow = f[++findex];
49613             Q = Qnew;
49614
49615             if (hh !== 0) {
49616               h[hindex++] = hh;
49617             }
49618           }
49619
49620           if (Q !== 0 || hindex === 0) {
49621             h[hindex++] = Q;
49622           }
49623
49624           return hindex;
49625         }
49626         function estimate(elen, e) {
49627           var Q = e[0];
49628
49629           for (var i = 1; i < elen; i++) {
49630             Q += e[i];
49631           }
49632
49633           return Q;
49634         }
49635         function vec(n) {
49636           return new Float64Array(n);
49637         }
49638
49639         var ccwerrboundA = (3 + 16 * epsilon$1) * epsilon$1;
49640         var ccwerrboundB = (2 + 12 * epsilon$1) * epsilon$1;
49641         var ccwerrboundC = (9 + 64 * epsilon$1) * epsilon$1 * epsilon$1;
49642         var B = vec(4);
49643         var C1 = vec(8);
49644         var C2 = vec(12);
49645         var D = vec(16);
49646         var u = vec(4);
49647
49648         function orient2dadapt(ax, ay, bx, by, cx, cy, detsum) {
49649           var acxtail, acytail, bcxtail, bcytail;
49650
49651           var bvirt, c, ahi, alo, bhi, blo, _i, _j, _0, s1, s0, t1, t0, u3;
49652
49653           var acx = ax - cx;
49654           var bcx = bx - cx;
49655           var acy = ay - cy;
49656           var bcy = by - cy;
49657           s1 = acx * bcy;
49658           c = splitter * acx;
49659           ahi = c - (c - acx);
49660           alo = acx - ahi;
49661           c = splitter * bcy;
49662           bhi = c - (c - bcy);
49663           blo = bcy - bhi;
49664           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
49665           t1 = acy * bcx;
49666           c = splitter * acy;
49667           ahi = c - (c - acy);
49668           alo = acy - ahi;
49669           c = splitter * bcx;
49670           bhi = c - (c - bcx);
49671           blo = bcx - bhi;
49672           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
49673           _i = s0 - t0;
49674           bvirt = s0 - _i;
49675           B[0] = s0 - (_i + bvirt) + (bvirt - t0);
49676           _j = s1 + _i;
49677           bvirt = _j - s1;
49678           _0 = s1 - (_j - bvirt) + (_i - bvirt);
49679           _i = _0 - t1;
49680           bvirt = _0 - _i;
49681           B[1] = _0 - (_i + bvirt) + (bvirt - t1);
49682           u3 = _j + _i;
49683           bvirt = u3 - _j;
49684           B[2] = _j - (u3 - bvirt) + (_i - bvirt);
49685           B[3] = u3;
49686           var det = estimate(4, B);
49687           var errbound = ccwerrboundB * detsum;
49688
49689           if (det >= errbound || -det >= errbound) {
49690             return det;
49691           }
49692
49693           bvirt = ax - acx;
49694           acxtail = ax - (acx + bvirt) + (bvirt - cx);
49695           bvirt = bx - bcx;
49696           bcxtail = bx - (bcx + bvirt) + (bvirt - cx);
49697           bvirt = ay - acy;
49698           acytail = ay - (acy + bvirt) + (bvirt - cy);
49699           bvirt = by - bcy;
49700           bcytail = by - (bcy + bvirt) + (bvirt - cy);
49701
49702           if (acxtail === 0 && acytail === 0 && bcxtail === 0 && bcytail === 0) {
49703             return det;
49704           }
49705
49706           errbound = ccwerrboundC * detsum + resulterrbound * Math.abs(det);
49707           det += acx * bcytail + bcy * acxtail - (acy * bcxtail + bcx * acytail);
49708           if (det >= errbound || -det >= errbound) return det;
49709           s1 = acxtail * bcy;
49710           c = splitter * acxtail;
49711           ahi = c - (c - acxtail);
49712           alo = acxtail - ahi;
49713           c = splitter * bcy;
49714           bhi = c - (c - bcy);
49715           blo = bcy - bhi;
49716           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
49717           t1 = acytail * bcx;
49718           c = splitter * acytail;
49719           ahi = c - (c - acytail);
49720           alo = acytail - ahi;
49721           c = splitter * bcx;
49722           bhi = c - (c - bcx);
49723           blo = bcx - bhi;
49724           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
49725           _i = s0 - t0;
49726           bvirt = s0 - _i;
49727           u[0] = s0 - (_i + bvirt) + (bvirt - t0);
49728           _j = s1 + _i;
49729           bvirt = _j - s1;
49730           _0 = s1 - (_j - bvirt) + (_i - bvirt);
49731           _i = _0 - t1;
49732           bvirt = _0 - _i;
49733           u[1] = _0 - (_i + bvirt) + (bvirt - t1);
49734           u3 = _j + _i;
49735           bvirt = u3 - _j;
49736           u[2] = _j - (u3 - bvirt) + (_i - bvirt);
49737           u[3] = u3;
49738           var C1len = sum(4, B, 4, u, C1);
49739           s1 = acx * bcytail;
49740           c = splitter * acx;
49741           ahi = c - (c - acx);
49742           alo = acx - ahi;
49743           c = splitter * bcytail;
49744           bhi = c - (c - bcytail);
49745           blo = bcytail - bhi;
49746           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
49747           t1 = acy * bcxtail;
49748           c = splitter * acy;
49749           ahi = c - (c - acy);
49750           alo = acy - ahi;
49751           c = splitter * bcxtail;
49752           bhi = c - (c - bcxtail);
49753           blo = bcxtail - bhi;
49754           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
49755           _i = s0 - t0;
49756           bvirt = s0 - _i;
49757           u[0] = s0 - (_i + bvirt) + (bvirt - t0);
49758           _j = s1 + _i;
49759           bvirt = _j - s1;
49760           _0 = s1 - (_j - bvirt) + (_i - bvirt);
49761           _i = _0 - t1;
49762           bvirt = _0 - _i;
49763           u[1] = _0 - (_i + bvirt) + (bvirt - t1);
49764           u3 = _j + _i;
49765           bvirt = u3 - _j;
49766           u[2] = _j - (u3 - bvirt) + (_i - bvirt);
49767           u[3] = u3;
49768           var C2len = sum(C1len, C1, 4, u, C2);
49769           s1 = acxtail * bcytail;
49770           c = splitter * acxtail;
49771           ahi = c - (c - acxtail);
49772           alo = acxtail - ahi;
49773           c = splitter * bcytail;
49774           bhi = c - (c - bcytail);
49775           blo = bcytail - bhi;
49776           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
49777           t1 = acytail * bcxtail;
49778           c = splitter * acytail;
49779           ahi = c - (c - acytail);
49780           alo = acytail - ahi;
49781           c = splitter * bcxtail;
49782           bhi = c - (c - bcxtail);
49783           blo = bcxtail - bhi;
49784           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
49785           _i = s0 - t0;
49786           bvirt = s0 - _i;
49787           u[0] = s0 - (_i + bvirt) + (bvirt - t0);
49788           _j = s1 + _i;
49789           bvirt = _j - s1;
49790           _0 = s1 - (_j - bvirt) + (_i - bvirt);
49791           _i = _0 - t1;
49792           bvirt = _0 - _i;
49793           u[1] = _0 - (_i + bvirt) + (bvirt - t1);
49794           u3 = _j + _i;
49795           bvirt = u3 - _j;
49796           u[2] = _j - (u3 - bvirt) + (_i - bvirt);
49797           u[3] = u3;
49798           var Dlen = sum(C2len, C2, 4, u, D);
49799           return D[Dlen - 1];
49800         }
49801
49802         function orient2d(ax, ay, bx, by, cx, cy) {
49803           var detleft = (ay - cy) * (bx - cx);
49804           var detright = (ax - cx) * (by - cy);
49805           var det = detleft - detright;
49806           if (detleft === 0 || detright === 0 || detleft > 0 !== detright > 0) return det;
49807           var detsum = Math.abs(detleft + detright);
49808           if (Math.abs(det) >= ccwerrboundA * detsum) return det;
49809           return -orient2dadapt(ax, ay, bx, by, cx, cy, detsum);
49810         }
49811
49812         /**
49813          * Signed area of the triangle (p0, p1, p2)
49814          * @param  {Array.<Number>} p0
49815          * @param  {Array.<Number>} p1
49816          * @param  {Array.<Number>} p2
49817          * @return {Number}
49818          */
49819
49820         function signedArea(p0, p1, p2) {
49821           var res = orient2d(p0[0], p0[1], p1[0], p1[1], p2[0], p2[1]);
49822           if (res > 0) return -1;
49823           if (res < 0) return 1;
49824           return 0;
49825         }
49826
49827         /**
49828          * @param  {SweepEvent} e1
49829          * @param  {SweepEvent} e2
49830          * @return {Number}
49831          */
49832
49833         function compareEvents(e1, e2) {
49834           var p1 = e1.point;
49835           var p2 = e2.point; // Different x-coordinate
49836
49837           if (p1[0] > p2[0]) return 1;
49838           if (p1[0] < p2[0]) return -1; // Different points, but same x-coordinate
49839           // Event with lower y-coordinate is processed first
49840
49841           if (p1[1] !== p2[1]) return p1[1] > p2[1] ? 1 : -1;
49842           return specialCases(e1, e2, p1);
49843         }
49844         /* eslint-disable no-unused-vars */
49845
49846         function specialCases(e1, e2, p1, p2) {
49847           // Same coordinates, but one is a left endpoint and the other is
49848           // a right endpoint. The right endpoint is processed first
49849           if (e1.left !== e2.left) return e1.left ? 1 : -1; // const p2 = e1.otherEvent.point, p3 = e2.otherEvent.point;
49850           // const sa = (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1])
49851           // Same coordinates, both events
49852           // are left endpoints or right endpoints.
49853           // not collinear
49854
49855           if (signedArea(p1, e1.otherEvent.point, e2.otherEvent.point) !== 0) {
49856             // the event associate to the bottom segment is processed first
49857             return !e1.isBelow(e2.otherEvent.point) ? 1 : -1;
49858           }
49859
49860           return !e1.isSubject && e2.isSubject ? 1 : -1;
49861         }
49862         /* eslint-enable no-unused-vars */
49863
49864         /**
49865          * @param  {SweepEvent} se
49866          * @param  {Array.<Number>} p
49867          * @param  {Queue} queue
49868          * @return {Queue}
49869          */
49870
49871         function divideSegment(se, p, queue) {
49872           var r = new SweepEvent(p, false, se, se.isSubject);
49873           var l = new SweepEvent(p, true, se.otherEvent, se.isSubject);
49874           /* eslint-disable no-console */
49875
49876           if (equals(se.point, se.otherEvent.point)) {
49877             console.warn('what is that, a collapsed segment?', se);
49878           }
49879           /* eslint-enable no-console */
49880
49881
49882           r.contourId = l.contourId = se.contourId; // avoid a rounding error. The left event would be processed after the right event
49883
49884           if (compareEvents(l, se.otherEvent) > 0) {
49885             se.otherEvent.left = true;
49886             l.left = false;
49887           } // avoid a rounding error. The left event would be processed after the right event
49888           // if (compareEvents(se, r) > 0) {}
49889
49890
49891           se.otherEvent.otherEvent = l;
49892           se.otherEvent = r;
49893           queue.push(l);
49894           queue.push(r);
49895           return queue;
49896         }
49897
49898         //const EPS = 1e-9;
49899
49900         /**
49901          * Finds the magnitude of the cross product of two vectors (if we pretend
49902          * they're in three dimensions)
49903          *
49904          * @param {Object} a First vector
49905          * @param {Object} b Second vector
49906          * @private
49907          * @returns {Number} The magnitude of the cross product
49908          */
49909         function crossProduct(a, b) {
49910           return a[0] * b[1] - a[1] * b[0];
49911         }
49912         /**
49913          * Finds the dot product of two vectors.
49914          *
49915          * @param {Object} a First vector
49916          * @param {Object} b Second vector
49917          * @private
49918          * @returns {Number} The dot product
49919          */
49920
49921
49922         function dotProduct(a, b) {
49923           return a[0] * b[0] + a[1] * b[1];
49924         }
49925         /**
49926          * Finds the intersection (if any) between two line segments a and b, given the
49927          * line segments' end points a1, a2 and b1, b2.
49928          *
49929          * This algorithm is based on Schneider and Eberly.
49930          * http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf
49931          * Page 244.
49932          *
49933          * @param {Array.<Number>} a1 point of first line
49934          * @param {Array.<Number>} a2 point of first line
49935          * @param {Array.<Number>} b1 point of second line
49936          * @param {Array.<Number>} b2 point of second line
49937          * @param {Boolean=}       noEndpointTouch whether to skip single touchpoints
49938          *                                         (meaning connected segments) as
49939          *                                         intersections
49940          * @returns {Array.<Array.<Number>>|Null} If the lines intersect, the point of
49941          * intersection. If they overlap, the two end points of the overlapping segment.
49942          * Otherwise, null.
49943          */
49944
49945
49946         function intersection (a1, a2, b1, b2, noEndpointTouch) {
49947           // The algorithm expects our lines in the form P + sd, where P is a point,
49948           // s is on the interval [0, 1], and d is a vector.
49949           // We are passed two points. P can be the first point of each pair. The
49950           // vector, then, could be thought of as the distance (in x and y components)
49951           // from the first point to the second point.
49952           // So first, let's make our vectors:
49953           var va = [a2[0] - a1[0], a2[1] - a1[1]];
49954           var vb = [b2[0] - b1[0], b2[1] - b1[1]]; // We also define a function to convert back to regular point form:
49955
49956           /* eslint-disable arrow-body-style */
49957
49958           function toPoint(p, s, d) {
49959             return [p[0] + s * d[0], p[1] + s * d[1]];
49960           }
49961           /* eslint-enable arrow-body-style */
49962           // The rest is pretty much a straight port of the algorithm.
49963
49964
49965           var e = [b1[0] - a1[0], b1[1] - a1[1]];
49966           var kross = crossProduct(va, vb);
49967           var sqrKross = kross * kross;
49968           var sqrLenA = dotProduct(va, va); //const sqrLenB  = dotProduct(vb, vb);
49969           // Check for line intersection. This works because of the properties of the
49970           // cross product -- specifically, two vectors are parallel if and only if the
49971           // cross product is the 0 vector. The full calculation involves relative error
49972           // to account for possible very small line segments. See Schneider & Eberly
49973           // for details.
49974
49975           if (sqrKross > 0
49976           /* EPS * sqrLenB * sqLenA */
49977           ) {
49978               // If they're not parallel, then (because these are line segments) they
49979               // still might not actually intersect. This code checks that the
49980               // intersection point of the lines is actually on both line segments.
49981               var s = crossProduct(e, vb) / kross;
49982
49983               if (s < 0 || s > 1) {
49984                 // not on line segment a
49985                 return null;
49986               }
49987
49988               var t = crossProduct(e, va) / kross;
49989
49990               if (t < 0 || t > 1) {
49991                 // not on line segment b
49992                 return null;
49993               }
49994
49995               if (s === 0 || s === 1) {
49996                 // on an endpoint of line segment a
49997                 return noEndpointTouch ? null : [toPoint(a1, s, va)];
49998               }
49999
50000               if (t === 0 || t === 1) {
50001                 // on an endpoint of line segment b
50002                 return noEndpointTouch ? null : [toPoint(b1, t, vb)];
50003               }
50004
50005               return [toPoint(a1, s, va)];
50006             } // If we've reached this point, then the lines are either parallel or the
50007           // same, but the segments could overlap partially or fully, or not at all.
50008           // So we need to find the overlap, if any. To do that, we can use e, which is
50009           // the (vector) difference between the two initial points. If this is parallel
50010           // with the line itself, then the two lines are the same line, and there will
50011           // be overlap.
50012           //const sqrLenE = dotProduct(e, e);
50013
50014
50015           kross = crossProduct(e, va);
50016           sqrKross = kross * kross;
50017
50018           if (sqrKross > 0
50019           /* EPS * sqLenB * sqLenE */
50020           ) {
50021               // Lines are just parallel, not the same. No overlap.
50022               return null;
50023             }
50024
50025           var sa = dotProduct(va, e) / sqrLenA;
50026           var sb = sa + dotProduct(va, vb) / sqrLenA;
50027           var smin = Math.min(sa, sb);
50028           var smax = Math.max(sa, sb); // this is, essentially, the FindIntersection acting on floats from
50029           // Schneider & Eberly, just inlined into this function.
50030
50031           if (smin <= 1 && smax >= 0) {
50032             // overlap on an end point
50033             if (smin === 1) {
50034               return noEndpointTouch ? null : [toPoint(a1, smin > 0 ? smin : 0, va)];
50035             }
50036
50037             if (smax === 0) {
50038               return noEndpointTouch ? null : [toPoint(a1, smax < 1 ? smax : 1, va)];
50039             }
50040
50041             if (noEndpointTouch && smin === 0 && smax === 1) return null; // There's overlap on a segment -- two points of intersection. Return both.
50042
50043             return [toPoint(a1, smin > 0 ? smin : 0, va), toPoint(a1, smax < 1 ? smax : 1, va)];
50044           }
50045
50046           return null;
50047         }
50048
50049         /**
50050          * @param  {SweepEvent} se1
50051          * @param  {SweepEvent} se2
50052          * @param  {Queue}      queue
50053          * @return {Number}
50054          */
50055
50056         function possibleIntersection(se1, se2, queue) {
50057           // that disallows self-intersecting polygons,
50058           // did cost us half a day, so I'll leave it
50059           // out of respect
50060           // if (se1.isSubject === se2.isSubject) return;
50061           var inter = intersection(se1.point, se1.otherEvent.point, se2.point, se2.otherEvent.point);
50062           var nintersections = inter ? inter.length : 0;
50063           if (nintersections === 0) return 0; // no intersection
50064           // the line segments intersect at an endpoint of both line segments
50065
50066           if (nintersections === 1 && (equals(se1.point, se2.point) || equals(se1.otherEvent.point, se2.otherEvent.point))) {
50067             return 0;
50068           }
50069
50070           if (nintersections === 2 && se1.isSubject === se2.isSubject) {
50071             // if(se1.contourId === se2.contourId){
50072             // console.warn('Edges of the same polygon overlap',
50073             //   se1.point, se1.otherEvent.point, se2.point, se2.otherEvent.point);
50074             // }
50075             //throw new Error('Edges of the same polygon overlap');
50076             return 0;
50077           } // The line segments associated to se1 and se2 intersect
50078
50079
50080           if (nintersections === 1) {
50081             // if the intersection point is not an endpoint of se1
50082             if (!equals(se1.point, inter[0]) && !equals(se1.otherEvent.point, inter[0])) {
50083               divideSegment(se1, inter[0], queue);
50084             } // if the intersection point is not an endpoint of se2
50085
50086
50087             if (!equals(se2.point, inter[0]) && !equals(se2.otherEvent.point, inter[0])) {
50088               divideSegment(se2, inter[0], queue);
50089             }
50090
50091             return 1;
50092           } // The line segments associated to se1 and se2 overlap
50093
50094
50095           var events = [];
50096           var leftCoincide = false;
50097           var rightCoincide = false;
50098
50099           if (equals(se1.point, se2.point)) {
50100             leftCoincide = true; // linked
50101           } else if (compareEvents(se1, se2) === 1) {
50102             events.push(se2, se1);
50103           } else {
50104             events.push(se1, se2);
50105           }
50106
50107           if (equals(se1.otherEvent.point, se2.otherEvent.point)) {
50108             rightCoincide = true;
50109           } else if (compareEvents(se1.otherEvent, se2.otherEvent) === 1) {
50110             events.push(se2.otherEvent, se1.otherEvent);
50111           } else {
50112             events.push(se1.otherEvent, se2.otherEvent);
50113           }
50114
50115           if (leftCoincide && rightCoincide || leftCoincide) {
50116             // both line segments are equal or share the left endpoint
50117             se2.type = NON_CONTRIBUTING;
50118             se1.type = se2.inOut === se1.inOut ? SAME_TRANSITION : DIFFERENT_TRANSITION;
50119
50120             if (leftCoincide && !rightCoincide) {
50121               // honestly no idea, but changing events selection from [2, 1]
50122               // to [0, 1] fixes the overlapping self-intersecting polygons issue
50123               divideSegment(events[1].otherEvent, events[0].point, queue);
50124             }
50125
50126             return 2;
50127           } // the line segments share the right endpoint
50128
50129
50130           if (rightCoincide) {
50131             divideSegment(events[0], events[1].point, queue);
50132             return 3;
50133           } // no line segment includes totally the other one
50134
50135
50136           if (events[0] !== events[3].otherEvent) {
50137             divideSegment(events[0], events[1].point, queue);
50138             divideSegment(events[1], events[2].point, queue);
50139             return 3;
50140           } // one line segment includes the other one
50141
50142
50143           divideSegment(events[0], events[1].point, queue);
50144           divideSegment(events[3].otherEvent, events[2].point, queue);
50145           return 3;
50146         }
50147
50148         /**
50149          * @param  {SweepEvent} le1
50150          * @param  {SweepEvent} le2
50151          * @return {Number}
50152          */
50153
50154         function compareSegments(le1, le2) {
50155           if (le1 === le2) return 0; // Segments are not collinear
50156
50157           if (signedArea(le1.point, le1.otherEvent.point, le2.point) !== 0 || signedArea(le1.point, le1.otherEvent.point, le2.otherEvent.point) !== 0) {
50158             // If they share their left endpoint use the right endpoint to sort
50159             if (equals(le1.point, le2.point)) return le1.isBelow(le2.otherEvent.point) ? -1 : 1; // Different left endpoint: use the left endpoint to sort
50160
50161             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
50162             // into S after the line segment associated to e2 ?
50163
50164             if (compareEvents(le1, le2) === 1) return le2.isAbove(le1.point) ? -1 : 1; // The line segment associated to e2 has been inserted
50165             // into S after the line segment associated to e1
50166
50167             return le1.isBelow(le2.point) ? -1 : 1;
50168           }
50169
50170           if (le1.isSubject === le2.isSubject) {
50171             // same polygon
50172             var p1 = le1.point,
50173                 p2 = le2.point;
50174
50175             if (p1[0] === p2[0] && p1[1] === p2[1]
50176             /*equals(le1.point, le2.point)*/
50177             ) {
50178                 p1 = le1.otherEvent.point;
50179                 p2 = le2.otherEvent.point;
50180                 if (p1[0] === p2[0] && p1[1] === p2[1]) return 0;else return le1.contourId > le2.contourId ? 1 : -1;
50181               }
50182           } else {
50183             // Segments are collinear, but belong to separate polygons
50184             return le1.isSubject ? -1 : 1;
50185           }
50186
50187           return compareEvents(le1, le2) === 1 ? 1 : -1;
50188         }
50189
50190         function subdivide(eventQueue, subject, clipping, sbbox, cbbox, operation) {
50191           var sweepLine = new SplayTree(compareSegments);
50192           var sortedEvents = [];
50193           var rightbound = Math.min(sbbox[2], cbbox[2]);
50194           var prev, next, begin;
50195
50196           while (eventQueue.length !== 0) {
50197             var event = eventQueue.pop();
50198             sortedEvents.push(event); // optimization by bboxes for intersection and difference goes here
50199
50200             if (operation === INTERSECTION && event.point[0] > rightbound || operation === DIFFERENCE && event.point[0] > sbbox[2]) {
50201               break;
50202             }
50203
50204             if (event.left) {
50205               next = prev = sweepLine.insert(event);
50206               begin = sweepLine.minNode();
50207               if (prev !== begin) prev = sweepLine.prev(prev);else prev = null;
50208               next = sweepLine.next(next);
50209               var prevEvent = prev ? prev.key : null;
50210               var prevprevEvent = void 0;
50211               computeFields(event, prevEvent, operation);
50212
50213               if (next) {
50214                 if (possibleIntersection(event, next.key, eventQueue) === 2) {
50215                   computeFields(event, prevEvent, operation);
50216                   computeFields(event, next.key, operation);
50217                 }
50218               }
50219
50220               if (prev) {
50221                 if (possibleIntersection(prev.key, event, eventQueue) === 2) {
50222                   var prevprev = prev;
50223                   if (prevprev !== begin) prevprev = sweepLine.prev(prevprev);else prevprev = null;
50224                   prevprevEvent = prevprev ? prevprev.key : null;
50225                   computeFields(prevEvent, prevprevEvent, operation);
50226                   computeFields(event, prevEvent, operation);
50227                 }
50228               }
50229             } else {
50230               event = event.otherEvent;
50231               next = prev = sweepLine.find(event);
50232
50233               if (prev && next) {
50234                 if (prev !== begin) prev = sweepLine.prev(prev);else prev = null;
50235                 next = sweepLine.next(next);
50236                 sweepLine.remove(event);
50237
50238                 if (next && prev) {
50239                   possibleIntersection(prev.key, next.key, eventQueue);
50240                 }
50241               }
50242             }
50243           }
50244
50245           return sortedEvents;
50246         }
50247
50248         var Contour = /*#__PURE__*/function () {
50249           /**
50250            * Contour
50251            *
50252            * @class {Contour}
50253            */
50254           function Contour() {
50255             _classCallCheck(this, Contour);
50256
50257             this.points = [];
50258             this.holeIds = [];
50259             this.holeOf = null;
50260             this.depth = null;
50261           }
50262
50263           _createClass(Contour, [{
50264             key: "isExterior",
50265             value: function isExterior() {
50266               return this.holeOf == null;
50267             }
50268           }]);
50269
50270           return Contour;
50271         }();
50272
50273         /**
50274          * @param  {Array.<SweepEvent>} sortedEvents
50275          * @return {Array.<SweepEvent>}
50276          */
50277
50278         function orderEvents(sortedEvents) {
50279           var event, i, len, tmp;
50280           var resultEvents = [];
50281
50282           for (i = 0, len = sortedEvents.length; i < len; i++) {
50283             event = sortedEvents[i];
50284
50285             if (event.left && event.inResult || !event.left && event.otherEvent.inResult) {
50286               resultEvents.push(event);
50287             }
50288           } // Due to overlapping edges the resultEvents array can be not wholly sorted
50289
50290
50291           var sorted = false;
50292
50293           while (!sorted) {
50294             sorted = true;
50295
50296             for (i = 0, len = resultEvents.length; i < len; i++) {
50297               if (i + 1 < len && compareEvents(resultEvents[i], resultEvents[i + 1]) === 1) {
50298                 tmp = resultEvents[i];
50299                 resultEvents[i] = resultEvents[i + 1];
50300                 resultEvents[i + 1] = tmp;
50301                 sorted = false;
50302               }
50303             }
50304           }
50305
50306           for (i = 0, len = resultEvents.length; i < len; i++) {
50307             event = resultEvents[i];
50308             event.otherPos = i;
50309           } // imagine, the right event is found in the beginning of the queue,
50310           // when his left counterpart is not marked yet
50311
50312
50313           for (i = 0, len = resultEvents.length; i < len; i++) {
50314             event = resultEvents[i];
50315
50316             if (!event.left) {
50317               tmp = event.otherPos;
50318               event.otherPos = event.otherEvent.otherPos;
50319               event.otherEvent.otherPos = tmp;
50320             }
50321           }
50322
50323           return resultEvents;
50324         }
50325         /**
50326          * @param  {Number} pos
50327          * @param  {Array.<SweepEvent>} resultEvents
50328          * @param  {Object>}    processed
50329          * @return {Number}
50330          */
50331
50332
50333         function nextPos(pos, resultEvents, processed, origPos) {
50334           var newPos = pos + 1,
50335               p = resultEvents[pos].point,
50336               p1;
50337           var length = resultEvents.length;
50338           if (newPos < length) p1 = resultEvents[newPos].point;
50339
50340           while (newPos < length && p1[0] === p[0] && p1[1] === p[1]) {
50341             if (!processed[newPos]) {
50342               return newPos;
50343             } else {
50344               newPos++;
50345             }
50346
50347             p1 = resultEvents[newPos].point;
50348           }
50349
50350           newPos = pos - 1;
50351
50352           while (processed[newPos] && newPos > origPos) {
50353             newPos--;
50354           }
50355
50356           return newPos;
50357         }
50358
50359         function initializeContourFromContext(event, contours, contourId) {
50360           var contour = new Contour();
50361
50362           if (event.prevInResult != null) {
50363             var prevInResult = event.prevInResult; // Note that it is valid to query the "previous in result" for its output contour id,
50364             // because we must have already processed it (i.e., assigned an output contour id)
50365             // in an earlier iteration, otherwise it wouldn't be possible that it is "previous in
50366             // result".
50367
50368             var lowerContourId = prevInResult.outputContourId;
50369             var lowerResultTransition = prevInResult.resultTransition;
50370
50371             if (lowerResultTransition > 0) {
50372               // We are inside. Now we have to check if the thing below us is another hole or
50373               // an exterior contour.
50374               var lowerContour = contours[lowerContourId];
50375
50376               if (lowerContour.holeOf != null) {
50377                 // The lower contour is a hole => Connect the new contour as a hole to its parent,
50378                 // and use same depth.
50379                 var parentContourId = lowerContour.holeOf;
50380                 contours[parentContourId].holeIds.push(contourId);
50381                 contour.holeOf = parentContourId;
50382                 contour.depth = contours[lowerContourId].depth;
50383               } else {
50384                 // The lower contour is an exterior contour => Connect the new contour as a hole,
50385                 // and increment depth.
50386                 contours[lowerContourId].holeIds.push(contourId);
50387                 contour.holeOf = lowerContourId;
50388                 contour.depth = contours[lowerContourId].depth + 1;
50389               }
50390             } else {
50391               // We are outside => this contour is an exterior contour of same depth.
50392               contour.holeOf = null;
50393               contour.depth = contours[lowerContourId].depth;
50394             }
50395           } else {
50396             // There is no lower/previous contour => this contour is an exterior contour of depth 0.
50397             contour.holeOf = null;
50398             contour.depth = 0;
50399           }
50400
50401           return contour;
50402         }
50403         /**
50404          * @param  {Array.<SweepEvent>} sortedEvents
50405          * @return {Array.<*>} polygons
50406          */
50407
50408
50409         function connectEdges(sortedEvents) {
50410           var i, len;
50411           var resultEvents = orderEvents(sortedEvents); // "false"-filled array
50412
50413           var processed = {};
50414           var contours = [];
50415
50416           var _loop = function _loop() {
50417             if (processed[i]) {
50418               return "continue";
50419             }
50420
50421             var contourId = contours.length;
50422             var contour = initializeContourFromContext(resultEvents[i], contours, contourId); // Helper function that combines marking an event as processed with assigning its output contour ID
50423
50424             var markAsProcessed = function markAsProcessed(pos) {
50425               processed[pos] = true;
50426               resultEvents[pos].outputContourId = contourId;
50427             };
50428
50429             var pos = i;
50430             var origPos = i;
50431             var initial = resultEvents[i].point;
50432             contour.points.push(initial);
50433             /* eslint no-constant-condition: "off" */
50434
50435             while (true) {
50436               markAsProcessed(pos);
50437               pos = resultEvents[pos].otherPos;
50438               markAsProcessed(pos);
50439               contour.points.push(resultEvents[pos].point);
50440               pos = nextPos(pos, resultEvents, processed, origPos);
50441
50442               if (pos == origPos) {
50443                 break;
50444               }
50445             }
50446
50447             contours.push(contour);
50448           };
50449
50450           for (i = 0, len = resultEvents.length; i < len; i++) {
50451             var _ret = _loop();
50452
50453             if (_ret === "continue") continue;
50454           }
50455
50456           return contours;
50457         }
50458
50459         var tinyqueue = TinyQueue;
50460         var _default$1 = TinyQueue;
50461
50462         function TinyQueue(data, compare) {
50463           if (!(this instanceof TinyQueue)) return new TinyQueue(data, compare);
50464           this.data = data || [];
50465           this.length = this.data.length;
50466           this.compare = compare || defaultCompare$1;
50467
50468           if (this.length > 0) {
50469             for (var i = (this.length >> 1) - 1; i >= 0; i--) {
50470               this._down(i);
50471             }
50472           }
50473         }
50474
50475         function defaultCompare$1(a, b) {
50476           return a < b ? -1 : a > b ? 1 : 0;
50477         }
50478
50479         TinyQueue.prototype = {
50480           push: function push(item) {
50481             this.data.push(item);
50482             this.length++;
50483
50484             this._up(this.length - 1);
50485           },
50486           pop: function pop() {
50487             if (this.length === 0) return undefined;
50488             var top = this.data[0];
50489             this.length--;
50490
50491             if (this.length > 0) {
50492               this.data[0] = this.data[this.length];
50493
50494               this._down(0);
50495             }
50496
50497             this.data.pop();
50498             return top;
50499           },
50500           peek: function peek() {
50501             return this.data[0];
50502           },
50503           _up: function _up(pos) {
50504             var data = this.data;
50505             var compare = this.compare;
50506             var item = data[pos];
50507
50508             while (pos > 0) {
50509               var parent = pos - 1 >> 1;
50510               var current = data[parent];
50511               if (compare(item, current) >= 0) break;
50512               data[pos] = current;
50513               pos = parent;
50514             }
50515
50516             data[pos] = item;
50517           },
50518           _down: function _down(pos) {
50519             var data = this.data;
50520             var compare = this.compare;
50521             var halfLength = this.length >> 1;
50522             var item = data[pos];
50523
50524             while (pos < halfLength) {
50525               var left = (pos << 1) + 1;
50526               var right = left + 1;
50527               var best = data[left];
50528
50529               if (right < this.length && compare(data[right], best) < 0) {
50530                 left = right;
50531                 best = data[right];
50532               }
50533
50534               if (compare(best, item) >= 0) break;
50535               data[pos] = best;
50536               pos = left;
50537             }
50538
50539             data[pos] = item;
50540           }
50541         };
50542         tinyqueue["default"] = _default$1;
50543
50544         var max$5 = Math.max;
50545         var min$a = Math.min;
50546         var contourId = 0;
50547
50548         function processPolygon(contourOrHole, isSubject, depth, Q, bbox, isExteriorRing) {
50549           var i, len, s1, s2, e1, e2;
50550
50551           for (i = 0, len = contourOrHole.length - 1; i < len; i++) {
50552             s1 = contourOrHole[i];
50553             s2 = contourOrHole[i + 1];
50554             e1 = new SweepEvent(s1, false, undefined, isSubject);
50555             e2 = new SweepEvent(s2, false, e1, isSubject);
50556             e1.otherEvent = e2;
50557
50558             if (s1[0] === s2[0] && s1[1] === s2[1]) {
50559               continue; // skip collapsed edges, or it breaks
50560             }
50561
50562             e1.contourId = e2.contourId = depth;
50563
50564             if (!isExteriorRing) {
50565               e1.isExteriorRing = false;
50566               e2.isExteriorRing = false;
50567             }
50568
50569             if (compareEvents(e1, e2) > 0) {
50570               e2.left = true;
50571             } else {
50572               e1.left = true;
50573             }
50574
50575             var x = s1[0],
50576                 y = s1[1];
50577             bbox[0] = min$a(bbox[0], x);
50578             bbox[1] = min$a(bbox[1], y);
50579             bbox[2] = max$5(bbox[2], x);
50580             bbox[3] = max$5(bbox[3], y); // Pushing it so the queue is sorted from left to right,
50581             // with object on the left having the highest priority.
50582
50583             Q.push(e1);
50584             Q.push(e2);
50585           }
50586         }
50587
50588         function fillQueue(subject, clipping, sbbox, cbbox, operation) {
50589           var eventQueue = new tinyqueue(null, compareEvents);
50590           var polygonSet, isExteriorRing, i, ii, j, jj; //, k, kk;
50591
50592           for (i = 0, ii = subject.length; i < ii; i++) {
50593             polygonSet = subject[i];
50594
50595             for (j = 0, jj = polygonSet.length; j < jj; j++) {
50596               isExteriorRing = j === 0;
50597               if (isExteriorRing) contourId++;
50598               processPolygon(polygonSet[j], true, contourId, eventQueue, sbbox, isExteriorRing);
50599             }
50600           }
50601
50602           for (i = 0, ii = clipping.length; i < ii; i++) {
50603             polygonSet = clipping[i];
50604
50605             for (j = 0, jj = polygonSet.length; j < jj; j++) {
50606               isExteriorRing = j === 0;
50607               if (operation === DIFFERENCE) isExteriorRing = false;
50608               if (isExteriorRing) contourId++;
50609               processPolygon(polygonSet[j], false, contourId, eventQueue, cbbox, isExteriorRing);
50610             }
50611           }
50612
50613           return eventQueue;
50614         }
50615
50616         var EMPTY = [];
50617
50618         function trivialOperation(subject, clipping, operation) {
50619           var result = null;
50620
50621           if (subject.length * clipping.length === 0) {
50622             if (operation === INTERSECTION) {
50623               result = EMPTY;
50624             } else if (operation === DIFFERENCE) {
50625               result = subject;
50626             } else if (operation === UNION || operation === XOR) {
50627               result = subject.length === 0 ? clipping : subject;
50628             }
50629           }
50630
50631           return result;
50632         }
50633
50634         function compareBBoxes(subject, clipping, sbbox, cbbox, operation) {
50635           var result = null;
50636
50637           if (sbbox[0] > cbbox[2] || cbbox[0] > sbbox[2] || sbbox[1] > cbbox[3] || cbbox[1] > sbbox[3]) {
50638             if (operation === INTERSECTION) {
50639               result = EMPTY;
50640             } else if (operation === DIFFERENCE) {
50641               result = subject;
50642             } else if (operation === UNION || operation === XOR) {
50643               result = subject.concat(clipping);
50644             }
50645           }
50646
50647           return result;
50648         }
50649
50650         function _boolean(subject, clipping, operation) {
50651           if (typeof subject[0][0][0] === 'number') {
50652             subject = [subject];
50653           }
50654
50655           if (typeof clipping[0][0][0] === 'number') {
50656             clipping = [clipping];
50657           }
50658
50659           var trivial = trivialOperation(subject, clipping, operation);
50660
50661           if (trivial) {
50662             return trivial === EMPTY ? null : trivial;
50663           }
50664
50665           var sbbox = [Infinity, Infinity, -Infinity, -Infinity];
50666           var cbbox = [Infinity, Infinity, -Infinity, -Infinity]; // console.time('fill queue');
50667
50668           var eventQueue = fillQueue(subject, clipping, sbbox, cbbox, operation); //console.timeEnd('fill queue');
50669
50670           trivial = compareBBoxes(subject, clipping, sbbox, cbbox, operation);
50671
50672           if (trivial) {
50673             return trivial === EMPTY ? null : trivial;
50674           } // console.time('subdivide edges');
50675
50676
50677           var sortedEvents = subdivide(eventQueue, subject, clipping, sbbox, cbbox, operation); //console.timeEnd('subdivide edges');
50678           // console.time('connect vertices');
50679
50680           var contours = connectEdges(sortedEvents); //console.timeEnd('connect vertices');
50681           // Convert contours to polygons
50682
50683           var polygons = [];
50684
50685           for (var i = 0; i < contours.length; i++) {
50686             var contour = contours[i];
50687
50688             if (contour.isExterior()) {
50689               // The exterior ring goes first
50690               var rings = [contour.points]; // Followed by holes if any
50691
50692               for (var j = 0; j < contour.holeIds.length; j++) {
50693                 var holeId = contour.holeIds[j];
50694                 rings.push(contours[holeId].points);
50695               }
50696
50697               polygons.push(rings);
50698             }
50699           }
50700
50701           return polygons;
50702         }
50703
50704         function union(subject, clipping) {
50705           return _boolean(subject, clipping, UNION);
50706         }
50707
50708         /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
50709         var read$6 = function read(buffer, offset, isLE, mLen, nBytes) {
50710           var e, m;
50711           var eLen = nBytes * 8 - mLen - 1;
50712           var eMax = (1 << eLen) - 1;
50713           var eBias = eMax >> 1;
50714           var nBits = -7;
50715           var i = isLE ? nBytes - 1 : 0;
50716           var d = isLE ? -1 : 1;
50717           var s = buffer[offset + i];
50718           i += d;
50719           e = s & (1 << -nBits) - 1;
50720           s >>= -nBits;
50721           nBits += eLen;
50722
50723           for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
50724
50725           m = e & (1 << -nBits) - 1;
50726           e >>= -nBits;
50727           nBits += mLen;
50728
50729           for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
50730
50731           if (e === 0) {
50732             e = 1 - eBias;
50733           } else if (e === eMax) {
50734             return m ? NaN : (s ? -1 : 1) * Infinity;
50735           } else {
50736             m = m + Math.pow(2, mLen);
50737             e = e - eBias;
50738           }
50739
50740           return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
50741         };
50742
50743         var write$6 = function write(buffer, value, offset, isLE, mLen, nBytes) {
50744           var e, m, c;
50745           var eLen = nBytes * 8 - mLen - 1;
50746           var eMax = (1 << eLen) - 1;
50747           var eBias = eMax >> 1;
50748           var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0;
50749           var i = isLE ? 0 : nBytes - 1;
50750           var d = isLE ? 1 : -1;
50751           var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0;
50752           value = Math.abs(value);
50753
50754           if (isNaN(value) || value === Infinity) {
50755             m = isNaN(value) ? 1 : 0;
50756             e = eMax;
50757           } else {
50758             e = Math.floor(Math.log(value) / Math.LN2);
50759
50760             if (value * (c = Math.pow(2, -e)) < 1) {
50761               e--;
50762               c *= 2;
50763             }
50764
50765             if (e + eBias >= 1) {
50766               value += rt / c;
50767             } else {
50768               value += rt * Math.pow(2, 1 - eBias);
50769             }
50770
50771             if (value * c >= 2) {
50772               e++;
50773               c /= 2;
50774             }
50775
50776             if (e + eBias >= eMax) {
50777               m = 0;
50778               e = eMax;
50779             } else if (e + eBias >= 1) {
50780               m = (value * c - 1) * Math.pow(2, mLen);
50781               e = e + eBias;
50782             } else {
50783               m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
50784               e = 0;
50785             }
50786           }
50787
50788           for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
50789
50790           e = e << mLen | m;
50791           eLen += mLen;
50792
50793           for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
50794
50795           buffer[offset + i - d] |= s * 128;
50796         };
50797
50798         var ieee754$1 = {
50799           read: read$6,
50800           write: write$6
50801         };
50802
50803         var pbf = Pbf;
50804
50805         function Pbf(buf) {
50806           this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);
50807           this.pos = 0;
50808           this.type = 0;
50809           this.length = this.buf.length;
50810         }
50811
50812         Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum
50813
50814         Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64
50815
50816         Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields
50817
50818         Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32
50819
50820         var SHIFT_LEFT_32 = (1 << 16) * (1 << 16),
50821             SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; // Threshold chosen based on both benchmarking and knowledge about browser string
50822         // data structures (which currently switch structure types at 12 bytes or more)
50823
50824         var TEXT_DECODER_MIN_LENGTH = 12;
50825         var utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf8');
50826         Pbf.prototype = {
50827           destroy: function destroy() {
50828             this.buf = null;
50829           },
50830           // === READING =================================================================
50831           readFields: function readFields(readField, result, end) {
50832             end = end || this.length;
50833
50834             while (this.pos < end) {
50835               var val = this.readVarint(),
50836                   tag = val >> 3,
50837                   startPos = this.pos;
50838               this.type = val & 0x7;
50839               readField(tag, result, this);
50840               if (this.pos === startPos) this.skip(val);
50841             }
50842
50843             return result;
50844           },
50845           readMessage: function readMessage(readField, result) {
50846             return this.readFields(readField, result, this.readVarint() + this.pos);
50847           },
50848           readFixed32: function readFixed32() {
50849             var val = readUInt32(this.buf, this.pos);
50850             this.pos += 4;
50851             return val;
50852           },
50853           readSFixed32: function readSFixed32() {
50854             var val = readInt32(this.buf, this.pos);
50855             this.pos += 4;
50856             return val;
50857           },
50858           // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
50859           readFixed64: function readFixed64() {
50860             var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
50861             this.pos += 8;
50862             return val;
50863           },
50864           readSFixed64: function readSFixed64() {
50865             var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
50866             this.pos += 8;
50867             return val;
50868           },
50869           readFloat: function readFloat() {
50870             var val = ieee754$1.read(this.buf, this.pos, true, 23, 4);
50871             this.pos += 4;
50872             return val;
50873           },
50874           readDouble: function readDouble() {
50875             var val = ieee754$1.read(this.buf, this.pos, true, 52, 8);
50876             this.pos += 8;
50877             return val;
50878           },
50879           readVarint: function readVarint(isSigned) {
50880             var buf = this.buf,
50881                 val,
50882                 b;
50883             b = buf[this.pos++];
50884             val = b & 0x7f;
50885             if (b < 0x80) return val;
50886             b = buf[this.pos++];
50887             val |= (b & 0x7f) << 7;
50888             if (b < 0x80) return val;
50889             b = buf[this.pos++];
50890             val |= (b & 0x7f) << 14;
50891             if (b < 0x80) return val;
50892             b = buf[this.pos++];
50893             val |= (b & 0x7f) << 21;
50894             if (b < 0x80) return val;
50895             b = buf[this.pos];
50896             val |= (b & 0x0f) << 28;
50897             return readVarintRemainder(val, isSigned, this);
50898           },
50899           readVarint64: function readVarint64() {
50900             // for compatibility with v2.0.1
50901             return this.readVarint(true);
50902           },
50903           readSVarint: function readSVarint() {
50904             var num = this.readVarint();
50905             return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding
50906           },
50907           readBoolean: function readBoolean() {
50908             return Boolean(this.readVarint());
50909           },
50910           readString: function readString() {
50911             var end = this.readVarint() + this.pos;
50912             var pos = this.pos;
50913             this.pos = end;
50914
50915             if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
50916               // longer strings are fast with the built-in browser TextDecoder API
50917               return readUtf8TextDecoder(this.buf, pos, end);
50918             } // short strings are fast with our custom implementation
50919
50920
50921             return readUtf8(this.buf, pos, end);
50922           },
50923           readBytes: function readBytes() {
50924             var end = this.readVarint() + this.pos,
50925                 buffer = this.buf.subarray(this.pos, end);
50926             this.pos = end;
50927             return buffer;
50928           },
50929           // verbose for performance reasons; doesn't affect gzipped size
50930           readPackedVarint: function readPackedVarint(arr, isSigned) {
50931             if (this.type !== Pbf.Bytes) return arr.push(this.readVarint(isSigned));
50932             var end = readPackedEnd(this);
50933             arr = arr || [];
50934
50935             while (this.pos < end) {
50936               arr.push(this.readVarint(isSigned));
50937             }
50938
50939             return arr;
50940           },
50941           readPackedSVarint: function readPackedSVarint(arr) {
50942             if (this.type !== Pbf.Bytes) return arr.push(this.readSVarint());
50943             var end = readPackedEnd(this);
50944             arr = arr || [];
50945
50946             while (this.pos < end) {
50947               arr.push(this.readSVarint());
50948             }
50949
50950             return arr;
50951           },
50952           readPackedBoolean: function readPackedBoolean(arr) {
50953             if (this.type !== Pbf.Bytes) return arr.push(this.readBoolean());
50954             var end = readPackedEnd(this);
50955             arr = arr || [];
50956
50957             while (this.pos < end) {
50958               arr.push(this.readBoolean());
50959             }
50960
50961             return arr;
50962           },
50963           readPackedFloat: function readPackedFloat(arr) {
50964             if (this.type !== Pbf.Bytes) return arr.push(this.readFloat());
50965             var end = readPackedEnd(this);
50966             arr = arr || [];
50967
50968             while (this.pos < end) {
50969               arr.push(this.readFloat());
50970             }
50971
50972             return arr;
50973           },
50974           readPackedDouble: function readPackedDouble(arr) {
50975             if (this.type !== Pbf.Bytes) return arr.push(this.readDouble());
50976             var end = readPackedEnd(this);
50977             arr = arr || [];
50978
50979             while (this.pos < end) {
50980               arr.push(this.readDouble());
50981             }
50982
50983             return arr;
50984           },
50985           readPackedFixed32: function readPackedFixed32(arr) {
50986             if (this.type !== Pbf.Bytes) return arr.push(this.readFixed32());
50987             var end = readPackedEnd(this);
50988             arr = arr || [];
50989
50990             while (this.pos < end) {
50991               arr.push(this.readFixed32());
50992             }
50993
50994             return arr;
50995           },
50996           readPackedSFixed32: function readPackedSFixed32(arr) {
50997             if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed32());
50998             var end = readPackedEnd(this);
50999             arr = arr || [];
51000
51001             while (this.pos < end) {
51002               arr.push(this.readSFixed32());
51003             }
51004
51005             return arr;
51006           },
51007           readPackedFixed64: function readPackedFixed64(arr) {
51008             if (this.type !== Pbf.Bytes) return arr.push(this.readFixed64());
51009             var end = readPackedEnd(this);
51010             arr = arr || [];
51011
51012             while (this.pos < end) {
51013               arr.push(this.readFixed64());
51014             }
51015
51016             return arr;
51017           },
51018           readPackedSFixed64: function readPackedSFixed64(arr) {
51019             if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed64());
51020             var end = readPackedEnd(this);
51021             arr = arr || [];
51022
51023             while (this.pos < end) {
51024               arr.push(this.readSFixed64());
51025             }
51026
51027             return arr;
51028           },
51029           skip: function skip(val) {
51030             var type = val & 0x7;
51031             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);
51032           },
51033           // === WRITING =================================================================
51034           writeTag: function writeTag(tag, type) {
51035             this.writeVarint(tag << 3 | type);
51036           },
51037           realloc: function realloc(min) {
51038             var length = this.length || 16;
51039
51040             while (length < this.pos + min) {
51041               length *= 2;
51042             }
51043
51044             if (length !== this.length) {
51045               var buf = new Uint8Array(length);
51046               buf.set(this.buf);
51047               this.buf = buf;
51048               this.length = length;
51049             }
51050           },
51051           finish: function finish() {
51052             this.length = this.pos;
51053             this.pos = 0;
51054             return this.buf.subarray(0, this.length);
51055           },
51056           writeFixed32: function writeFixed32(val) {
51057             this.realloc(4);
51058             writeInt32(this.buf, val, this.pos);
51059             this.pos += 4;
51060           },
51061           writeSFixed32: function writeSFixed32(val) {
51062             this.realloc(4);
51063             writeInt32(this.buf, val, this.pos);
51064             this.pos += 4;
51065           },
51066           writeFixed64: function writeFixed64(val) {
51067             this.realloc(8);
51068             writeInt32(this.buf, val & -1, this.pos);
51069             writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
51070             this.pos += 8;
51071           },
51072           writeSFixed64: function writeSFixed64(val) {
51073             this.realloc(8);
51074             writeInt32(this.buf, val & -1, this.pos);
51075             writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
51076             this.pos += 8;
51077           },
51078           writeVarint: function writeVarint(val) {
51079             val = +val || 0;
51080
51081             if (val > 0xfffffff || val < 0) {
51082               writeBigVarint(val, this);
51083               return;
51084             }
51085
51086             this.realloc(4);
51087             this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0);
51088             if (val <= 0x7f) return;
51089             this.buf[this.pos++] = (val >>>= 7) & 0x7f | (val > 0x7f ? 0x80 : 0);
51090             if (val <= 0x7f) return;
51091             this.buf[this.pos++] = (val >>>= 7) & 0x7f | (val > 0x7f ? 0x80 : 0);
51092             if (val <= 0x7f) return;
51093             this.buf[this.pos++] = val >>> 7 & 0x7f;
51094           },
51095           writeSVarint: function writeSVarint(val) {
51096             this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
51097           },
51098           writeBoolean: function writeBoolean(val) {
51099             this.writeVarint(Boolean(val));
51100           },
51101           writeString: function writeString(str) {
51102             str = String(str);
51103             this.realloc(str.length * 4);
51104             this.pos++; // reserve 1 byte for short string length
51105
51106             var startPos = this.pos; // write the string directly to the buffer and see how much was written
51107
51108             this.pos = writeUtf8(this.buf, str, this.pos);
51109             var len = this.pos - startPos;
51110             if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position
51111
51112             this.pos = startPos - 1;
51113             this.writeVarint(len);
51114             this.pos += len;
51115           },
51116           writeFloat: function writeFloat(val) {
51117             this.realloc(4);
51118             ieee754$1.write(this.buf, val, this.pos, true, 23, 4);
51119             this.pos += 4;
51120           },
51121           writeDouble: function writeDouble(val) {
51122             this.realloc(8);
51123             ieee754$1.write(this.buf, val, this.pos, true, 52, 8);
51124             this.pos += 8;
51125           },
51126           writeBytes: function writeBytes(buffer) {
51127             var len = buffer.length;
51128             this.writeVarint(len);
51129             this.realloc(len);
51130
51131             for (var i = 0; i < len; i++) {
51132               this.buf[this.pos++] = buffer[i];
51133             }
51134           },
51135           writeRawMessage: function writeRawMessage(fn, obj) {
51136             this.pos++; // reserve 1 byte for short message length
51137             // write the message directly to the buffer and see how much was written
51138
51139             var startPos = this.pos;
51140             fn(obj, this);
51141             var len = this.pos - startPos;
51142             if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position
51143
51144             this.pos = startPos - 1;
51145             this.writeVarint(len);
51146             this.pos += len;
51147           },
51148           writeMessage: function writeMessage(tag, fn, obj) {
51149             this.writeTag(tag, Pbf.Bytes);
51150             this.writeRawMessage(fn, obj);
51151           },
51152           writePackedVarint: function writePackedVarint(tag, arr) {
51153             if (arr.length) this.writeMessage(tag, _writePackedVarint, arr);
51154           },
51155           writePackedSVarint: function writePackedSVarint(tag, arr) {
51156             if (arr.length) this.writeMessage(tag, _writePackedSVarint, arr);
51157           },
51158           writePackedBoolean: function writePackedBoolean(tag, arr) {
51159             if (arr.length) this.writeMessage(tag, _writePackedBoolean, arr);
51160           },
51161           writePackedFloat: function writePackedFloat(tag, arr) {
51162             if (arr.length) this.writeMessage(tag, _writePackedFloat, arr);
51163           },
51164           writePackedDouble: function writePackedDouble(tag, arr) {
51165             if (arr.length) this.writeMessage(tag, _writePackedDouble, arr);
51166           },
51167           writePackedFixed32: function writePackedFixed32(tag, arr) {
51168             if (arr.length) this.writeMessage(tag, _writePackedFixed, arr);
51169           },
51170           writePackedSFixed32: function writePackedSFixed32(tag, arr) {
51171             if (arr.length) this.writeMessage(tag, _writePackedSFixed, arr);
51172           },
51173           writePackedFixed64: function writePackedFixed64(tag, arr) {
51174             if (arr.length) this.writeMessage(tag, _writePackedFixed2, arr);
51175           },
51176           writePackedSFixed64: function writePackedSFixed64(tag, arr) {
51177             if (arr.length) this.writeMessage(tag, _writePackedSFixed2, arr);
51178           },
51179           writeBytesField: function writeBytesField(tag, buffer) {
51180             this.writeTag(tag, Pbf.Bytes);
51181             this.writeBytes(buffer);
51182           },
51183           writeFixed32Field: function writeFixed32Field(tag, val) {
51184             this.writeTag(tag, Pbf.Fixed32);
51185             this.writeFixed32(val);
51186           },
51187           writeSFixed32Field: function writeSFixed32Field(tag, val) {
51188             this.writeTag(tag, Pbf.Fixed32);
51189             this.writeSFixed32(val);
51190           },
51191           writeFixed64Field: function writeFixed64Field(tag, val) {
51192             this.writeTag(tag, Pbf.Fixed64);
51193             this.writeFixed64(val);
51194           },
51195           writeSFixed64Field: function writeSFixed64Field(tag, val) {
51196             this.writeTag(tag, Pbf.Fixed64);
51197             this.writeSFixed64(val);
51198           },
51199           writeVarintField: function writeVarintField(tag, val) {
51200             this.writeTag(tag, Pbf.Varint);
51201             this.writeVarint(val);
51202           },
51203           writeSVarintField: function writeSVarintField(tag, val) {
51204             this.writeTag(tag, Pbf.Varint);
51205             this.writeSVarint(val);
51206           },
51207           writeStringField: function writeStringField(tag, str) {
51208             this.writeTag(tag, Pbf.Bytes);
51209             this.writeString(str);
51210           },
51211           writeFloatField: function writeFloatField(tag, val) {
51212             this.writeTag(tag, Pbf.Fixed32);
51213             this.writeFloat(val);
51214           },
51215           writeDoubleField: function writeDoubleField(tag, val) {
51216             this.writeTag(tag, Pbf.Fixed64);
51217             this.writeDouble(val);
51218           },
51219           writeBooleanField: function writeBooleanField(tag, val) {
51220             this.writeVarintField(tag, Boolean(val));
51221           }
51222         };
51223
51224         function readVarintRemainder(l, s, p) {
51225           var buf = p.buf,
51226               h,
51227               b;
51228           b = buf[p.pos++];
51229           h = (b & 0x70) >> 4;
51230           if (b < 0x80) return toNum(l, h, s);
51231           b = buf[p.pos++];
51232           h |= (b & 0x7f) << 3;
51233           if (b < 0x80) return toNum(l, h, s);
51234           b = buf[p.pos++];
51235           h |= (b & 0x7f) << 10;
51236           if (b < 0x80) return toNum(l, h, s);
51237           b = buf[p.pos++];
51238           h |= (b & 0x7f) << 17;
51239           if (b < 0x80) return toNum(l, h, s);
51240           b = buf[p.pos++];
51241           h |= (b & 0x7f) << 24;
51242           if (b < 0x80) return toNum(l, h, s);
51243           b = buf[p.pos++];
51244           h |= (b & 0x01) << 31;
51245           if (b < 0x80) return toNum(l, h, s);
51246           throw new Error('Expected varint not more than 10 bytes');
51247         }
51248
51249         function readPackedEnd(pbf) {
51250           return pbf.type === Pbf.Bytes ? pbf.readVarint() + pbf.pos : pbf.pos + 1;
51251         }
51252
51253         function toNum(low, high, isSigned) {
51254           if (isSigned) {
51255             return high * 0x100000000 + (low >>> 0);
51256           }
51257
51258           return (high >>> 0) * 0x100000000 + (low >>> 0);
51259         }
51260
51261         function writeBigVarint(val, pbf) {
51262           var low, high;
51263
51264           if (val >= 0) {
51265             low = val % 0x100000000 | 0;
51266             high = val / 0x100000000 | 0;
51267           } else {
51268             low = ~(-val % 0x100000000);
51269             high = ~(-val / 0x100000000);
51270
51271             if (low ^ 0xffffffff) {
51272               low = low + 1 | 0;
51273             } else {
51274               low = 0;
51275               high = high + 1 | 0;
51276             }
51277           }
51278
51279           if (val >= 0x10000000000000000 || val < -0x10000000000000000) {
51280             throw new Error('Given varint doesn\'t fit into 10 bytes');
51281           }
51282
51283           pbf.realloc(10);
51284           writeBigVarintLow(low, high, pbf);
51285           writeBigVarintHigh(high, pbf);
51286         }
51287
51288         function writeBigVarintLow(low, high, pbf) {
51289           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51290           low >>>= 7;
51291           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51292           low >>>= 7;
51293           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51294           low >>>= 7;
51295           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51296           low >>>= 7;
51297           pbf.buf[pbf.pos] = low & 0x7f;
51298         }
51299
51300         function writeBigVarintHigh(high, pbf) {
51301           var lsb = (high & 0x07) << 4;
51302           pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0);
51303           if (!high) return;
51304           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51305           if (!high) return;
51306           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51307           if (!high) return;
51308           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51309           if (!high) return;
51310           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51311           if (!high) return;
51312           pbf.buf[pbf.pos++] = high & 0x7f;
51313         }
51314
51315         function makeRoomForExtraLength(startPos, len, pbf) {
51316           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
51317
51318           pbf.realloc(extraLen);
51319
51320           for (var i = pbf.pos - 1; i >= startPos; i--) {
51321             pbf.buf[i + extraLen] = pbf.buf[i];
51322           }
51323         }
51324
51325         function _writePackedVarint(arr, pbf) {
51326           for (var i = 0; i < arr.length; i++) {
51327             pbf.writeVarint(arr[i]);
51328           }
51329         }
51330
51331         function _writePackedSVarint(arr, pbf) {
51332           for (var i = 0; i < arr.length; i++) {
51333             pbf.writeSVarint(arr[i]);
51334           }
51335         }
51336
51337         function _writePackedFloat(arr, pbf) {
51338           for (var i = 0; i < arr.length; i++) {
51339             pbf.writeFloat(arr[i]);
51340           }
51341         }
51342
51343         function _writePackedDouble(arr, pbf) {
51344           for (var i = 0; i < arr.length; i++) {
51345             pbf.writeDouble(arr[i]);
51346           }
51347         }
51348
51349         function _writePackedBoolean(arr, pbf) {
51350           for (var i = 0; i < arr.length; i++) {
51351             pbf.writeBoolean(arr[i]);
51352           }
51353         }
51354
51355         function _writePackedFixed(arr, pbf) {
51356           for (var i = 0; i < arr.length; i++) {
51357             pbf.writeFixed32(arr[i]);
51358           }
51359         }
51360
51361         function _writePackedSFixed(arr, pbf) {
51362           for (var i = 0; i < arr.length; i++) {
51363             pbf.writeSFixed32(arr[i]);
51364           }
51365         }
51366
51367         function _writePackedFixed2(arr, pbf) {
51368           for (var i = 0; i < arr.length; i++) {
51369             pbf.writeFixed64(arr[i]);
51370           }
51371         }
51372
51373         function _writePackedSFixed2(arr, pbf) {
51374           for (var i = 0; i < arr.length; i++) {
51375             pbf.writeSFixed64(arr[i]);
51376           }
51377         } // Buffer code below from https://github.com/feross/buffer, MIT-licensed
51378
51379
51380         function readUInt32(buf, pos) {
51381           return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + buf[pos + 3] * 0x1000000;
51382         }
51383
51384         function writeInt32(buf, val, pos) {
51385           buf[pos] = val;
51386           buf[pos + 1] = val >>> 8;
51387           buf[pos + 2] = val >>> 16;
51388           buf[pos + 3] = val >>> 24;
51389         }
51390
51391         function readInt32(buf, pos) {
51392           return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + (buf[pos + 3] << 24);
51393         }
51394
51395         function readUtf8(buf, pos, end) {
51396           var str = '';
51397           var i = pos;
51398
51399           while (i < end) {
51400             var b0 = buf[i];
51401             var c = null; // codepoint
51402
51403             var bytesPerSequence = b0 > 0xEF ? 4 : b0 > 0xDF ? 3 : b0 > 0xBF ? 2 : 1;
51404             if (i + bytesPerSequence > end) break;
51405             var b1, b2, b3;
51406
51407             if (bytesPerSequence === 1) {
51408               if (b0 < 0x80) {
51409                 c = b0;
51410               }
51411             } else if (bytesPerSequence === 2) {
51412               b1 = buf[i + 1];
51413
51414               if ((b1 & 0xC0) === 0x80) {
51415                 c = (b0 & 0x1F) << 0x6 | b1 & 0x3F;
51416
51417                 if (c <= 0x7F) {
51418                   c = null;
51419                 }
51420               }
51421             } else if (bytesPerSequence === 3) {
51422               b1 = buf[i + 1];
51423               b2 = buf[i + 2];
51424
51425               if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) {
51426                 c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | b2 & 0x3F;
51427
51428                 if (c <= 0x7FF || c >= 0xD800 && c <= 0xDFFF) {
51429                   c = null;
51430                 }
51431               }
51432             } else if (bytesPerSequence === 4) {
51433               b1 = buf[i + 1];
51434               b2 = buf[i + 2];
51435               b3 = buf[i + 3];
51436
51437               if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {
51438                 c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | b3 & 0x3F;
51439
51440                 if (c <= 0xFFFF || c >= 0x110000) {
51441                   c = null;
51442                 }
51443               }
51444             }
51445
51446             if (c === null) {
51447               c = 0xFFFD;
51448               bytesPerSequence = 1;
51449             } else if (c > 0xFFFF) {
51450               c -= 0x10000;
51451               str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800);
51452               c = 0xDC00 | c & 0x3FF;
51453             }
51454
51455             str += String.fromCharCode(c);
51456             i += bytesPerSequence;
51457           }
51458
51459           return str;
51460         }
51461
51462         function readUtf8TextDecoder(buf, pos, end) {
51463           return utf8TextDecoder.decode(buf.subarray(pos, end));
51464         }
51465
51466         function writeUtf8(buf, str, pos) {
51467           for (var i = 0, c, lead; i < str.length; i++) {
51468             c = str.charCodeAt(i); // code point
51469
51470             if (c > 0xD7FF && c < 0xE000) {
51471               if (lead) {
51472                 if (c < 0xDC00) {
51473                   buf[pos++] = 0xEF;
51474                   buf[pos++] = 0xBF;
51475                   buf[pos++] = 0xBD;
51476                   lead = c;
51477                   continue;
51478                 } else {
51479                   c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000;
51480                   lead = null;
51481                 }
51482               } else {
51483                 if (c > 0xDBFF || i + 1 === str.length) {
51484                   buf[pos++] = 0xEF;
51485                   buf[pos++] = 0xBF;
51486                   buf[pos++] = 0xBD;
51487                 } else {
51488                   lead = c;
51489                 }
51490
51491                 continue;
51492               }
51493             } else if (lead) {
51494               buf[pos++] = 0xEF;
51495               buf[pos++] = 0xBF;
51496               buf[pos++] = 0xBD;
51497               lead = null;
51498             }
51499
51500             if (c < 0x80) {
51501               buf[pos++] = c;
51502             } else {
51503               if (c < 0x800) {
51504                 buf[pos++] = c >> 0x6 | 0xC0;
51505               } else {
51506                 if (c < 0x10000) {
51507                   buf[pos++] = c >> 0xC | 0xE0;
51508                 } else {
51509                   buf[pos++] = c >> 0x12 | 0xF0;
51510                   buf[pos++] = c >> 0xC & 0x3F | 0x80;
51511                 }
51512
51513                 buf[pos++] = c >> 0x6 & 0x3F | 0x80;
51514               }
51515
51516               buf[pos++] = c & 0x3F | 0x80;
51517             }
51518           }
51519
51520           return pos;
51521         }
51522
51523         var pointGeometry = Point;
51524         /**
51525          * A standalone point geometry with useful accessor, comparison, and
51526          * modification methods.
51527          *
51528          * @class Point
51529          * @param {Number} x the x-coordinate. this could be longitude or screen
51530          * pixels, or any other sort of unit.
51531          * @param {Number} y the y-coordinate. this could be latitude or screen
51532          * pixels, or any other sort of unit.
51533          * @example
51534          * var point = new Point(-77, 38);
51535          */
51536
51537         function Point(x, y) {
51538           this.x = x;
51539           this.y = y;
51540         }
51541
51542         Point.prototype = {
51543           /**
51544            * Clone this point, returning a new point that can be modified
51545            * without affecting the old one.
51546            * @return {Point} the clone
51547            */
51548           clone: function clone() {
51549             return new Point(this.x, this.y);
51550           },
51551
51552           /**
51553            * Add this point's x & y coordinates to another point,
51554            * yielding a new point.
51555            * @param {Point} p the other point
51556            * @return {Point} output point
51557            */
51558           add: function add(p) {
51559             return this.clone()._add(p);
51560           },
51561
51562           /**
51563            * Subtract this point's x & y coordinates to from point,
51564            * yielding a new point.
51565            * @param {Point} p the other point
51566            * @return {Point} output point
51567            */
51568           sub: function sub(p) {
51569             return this.clone()._sub(p);
51570           },
51571
51572           /**
51573            * Multiply this point's x & y coordinates by point,
51574            * yielding a new point.
51575            * @param {Point} p the other point
51576            * @return {Point} output point
51577            */
51578           multByPoint: function multByPoint(p) {
51579             return this.clone()._multByPoint(p);
51580           },
51581
51582           /**
51583            * Divide this point's x & y coordinates by point,
51584            * yielding a new point.
51585            * @param {Point} p the other point
51586            * @return {Point} output point
51587            */
51588           divByPoint: function divByPoint(p) {
51589             return this.clone()._divByPoint(p);
51590           },
51591
51592           /**
51593            * Multiply this point's x & y coordinates by a factor,
51594            * yielding a new point.
51595            * @param {Point} k factor
51596            * @return {Point} output point
51597            */
51598           mult: function mult(k) {
51599             return this.clone()._mult(k);
51600           },
51601
51602           /**
51603            * Divide this point's x & y coordinates by a factor,
51604            * yielding a new point.
51605            * @param {Point} k factor
51606            * @return {Point} output point
51607            */
51608           div: function div(k) {
51609             return this.clone()._div(k);
51610           },
51611
51612           /**
51613            * Rotate this point around the 0, 0 origin by an angle a,
51614            * given in radians
51615            * @param {Number} a angle to rotate around, in radians
51616            * @return {Point} output point
51617            */
51618           rotate: function rotate(a) {
51619             return this.clone()._rotate(a);
51620           },
51621
51622           /**
51623            * Rotate this point around p point by an angle a,
51624            * given in radians
51625            * @param {Number} a angle to rotate around, in radians
51626            * @param {Point} p Point to rotate around
51627            * @return {Point} output point
51628            */
51629           rotateAround: function rotateAround(a, p) {
51630             return this.clone()._rotateAround(a, p);
51631           },
51632
51633           /**
51634            * Multiply this point by a 4x1 transformation matrix
51635            * @param {Array<Number>} m transformation matrix
51636            * @return {Point} output point
51637            */
51638           matMult: function matMult(m) {
51639             return this.clone()._matMult(m);
51640           },
51641
51642           /**
51643            * Calculate this point but as a unit vector from 0, 0, meaning
51644            * that the distance from the resulting point to the 0, 0
51645            * coordinate will be equal to 1 and the angle from the resulting
51646            * point to the 0, 0 coordinate will be the same as before.
51647            * @return {Point} unit vector point
51648            */
51649           unit: function unit() {
51650             return this.clone()._unit();
51651           },
51652
51653           /**
51654            * Compute a perpendicular point, where the new y coordinate
51655            * is the old x coordinate and the new x coordinate is the old y
51656            * coordinate multiplied by -1
51657            * @return {Point} perpendicular point
51658            */
51659           perp: function perp() {
51660             return this.clone()._perp();
51661           },
51662
51663           /**
51664            * Return a version of this point with the x & y coordinates
51665            * rounded to integers.
51666            * @return {Point} rounded point
51667            */
51668           round: function round() {
51669             return this.clone()._round();
51670           },
51671
51672           /**
51673            * Return the magitude of this point: this is the Euclidean
51674            * distance from the 0, 0 coordinate to this point's x and y
51675            * coordinates.
51676            * @return {Number} magnitude
51677            */
51678           mag: function mag() {
51679             return Math.sqrt(this.x * this.x + this.y * this.y);
51680           },
51681
51682           /**
51683            * Judge whether this point is equal to another point, returning
51684            * true or false.
51685            * @param {Point} other the other point
51686            * @return {boolean} whether the points are equal
51687            */
51688           equals: function equals(other) {
51689             return this.x === other.x && this.y === other.y;
51690           },
51691
51692           /**
51693            * Calculate the distance from this point to another point
51694            * @param {Point} p the other point
51695            * @return {Number} distance
51696            */
51697           dist: function dist(p) {
51698             return Math.sqrt(this.distSqr(p));
51699           },
51700
51701           /**
51702            * Calculate the distance from this point to another point,
51703            * without the square root step. Useful if you're comparing
51704            * relative distances.
51705            * @param {Point} p the other point
51706            * @return {Number} distance
51707            */
51708           distSqr: function distSqr(p) {
51709             var dx = p.x - this.x,
51710                 dy = p.y - this.y;
51711             return dx * dx + dy * dy;
51712           },
51713
51714           /**
51715            * Get the angle from the 0, 0 coordinate to this point, in radians
51716            * coordinates.
51717            * @return {Number} angle
51718            */
51719           angle: function angle() {
51720             return Math.atan2(this.y, this.x);
51721           },
51722
51723           /**
51724            * Get the angle from this point to another point, in radians
51725            * @param {Point} b the other point
51726            * @return {Number} angle
51727            */
51728           angleTo: function angleTo(b) {
51729             return Math.atan2(this.y - b.y, this.x - b.x);
51730           },
51731
51732           /**
51733            * Get the angle between this point and another point, in radians
51734            * @param {Point} b the other point
51735            * @return {Number} angle
51736            */
51737           angleWith: function angleWith(b) {
51738             return this.angleWithSep(b.x, b.y);
51739           },
51740
51741           /*
51742            * Find the angle of the two vectors, solving the formula for
51743            * the cross product a x b = |a||b|sin(θ) for θ.
51744            * @param {Number} x the x-coordinate
51745            * @param {Number} y the y-coordinate
51746            * @return {Number} the angle in radians
51747            */
51748           angleWithSep: function angleWithSep(x, y) {
51749             return Math.atan2(this.x * y - this.y * x, this.x * x + this.y * y);
51750           },
51751           _matMult: function _matMult(m) {
51752             var x = m[0] * this.x + m[1] * this.y,
51753                 y = m[2] * this.x + m[3] * this.y;
51754             this.x = x;
51755             this.y = y;
51756             return this;
51757           },
51758           _add: function _add(p) {
51759             this.x += p.x;
51760             this.y += p.y;
51761             return this;
51762           },
51763           _sub: function _sub(p) {
51764             this.x -= p.x;
51765             this.y -= p.y;
51766             return this;
51767           },
51768           _mult: function _mult(k) {
51769             this.x *= k;
51770             this.y *= k;
51771             return this;
51772           },
51773           _div: function _div(k) {
51774             this.x /= k;
51775             this.y /= k;
51776             return this;
51777           },
51778           _multByPoint: function _multByPoint(p) {
51779             this.x *= p.x;
51780             this.y *= p.y;
51781             return this;
51782           },
51783           _divByPoint: function _divByPoint(p) {
51784             this.x /= p.x;
51785             this.y /= p.y;
51786             return this;
51787           },
51788           _unit: function _unit() {
51789             this._div(this.mag());
51790
51791             return this;
51792           },
51793           _perp: function _perp() {
51794             var y = this.y;
51795             this.y = this.x;
51796             this.x = -y;
51797             return this;
51798           },
51799           _rotate: function _rotate(angle) {
51800             var cos = Math.cos(angle),
51801                 sin = Math.sin(angle),
51802                 x = cos * this.x - sin * this.y,
51803                 y = sin * this.x + cos * this.y;
51804             this.x = x;
51805             this.y = y;
51806             return this;
51807           },
51808           _rotateAround: function _rotateAround(angle, p) {
51809             var cos = Math.cos(angle),
51810                 sin = Math.sin(angle),
51811                 x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y),
51812                 y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y);
51813             this.x = x;
51814             this.y = y;
51815             return this;
51816           },
51817           _round: function _round() {
51818             this.x = Math.round(this.x);
51819             this.y = Math.round(this.y);
51820             return this;
51821           }
51822         };
51823         /**
51824          * Construct a point from an array if necessary, otherwise if the input
51825          * is already a Point, or an unknown type, return it unchanged
51826          * @param {Array<Number>|Point|*} a any kind of input value
51827          * @return {Point} constructed point, or passed-through value.
51828          * @example
51829          * // this
51830          * var point = Point.convert([0, 1]);
51831          * // is equivalent to
51832          * var point = new Point(0, 1);
51833          */
51834
51835         Point.convert = function (a) {
51836           if (a instanceof Point) {
51837             return a;
51838           }
51839
51840           if (Array.isArray(a)) {
51841             return new Point(a[0], a[1]);
51842           }
51843
51844           return a;
51845         };
51846
51847         var vectortilefeature = VectorTileFeature;
51848
51849         function VectorTileFeature(pbf, end, extent, keys, values) {
51850           // Public
51851           this.properties = {};
51852           this.extent = extent;
51853           this.type = 0; // Private
51854
51855           this._pbf = pbf;
51856           this._geometry = -1;
51857           this._keys = keys;
51858           this._values = values;
51859           pbf.readFields(readFeature, this, end);
51860         }
51861
51862         function readFeature(tag, feature, pbf) {
51863           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;
51864         }
51865
51866         function readTag(pbf, feature) {
51867           var end = pbf.readVarint() + pbf.pos;
51868
51869           while (pbf.pos < end) {
51870             var key = feature._keys[pbf.readVarint()],
51871                 value = feature._values[pbf.readVarint()];
51872
51873             feature.properties[key] = value;
51874           }
51875         }
51876
51877         VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon'];
51878
51879         VectorTileFeature.prototype.loadGeometry = function () {
51880           var pbf = this._pbf;
51881           pbf.pos = this._geometry;
51882           var end = pbf.readVarint() + pbf.pos,
51883               cmd = 1,
51884               length = 0,
51885               x = 0,
51886               y = 0,
51887               lines = [],
51888               line;
51889
51890           while (pbf.pos < end) {
51891             if (length <= 0) {
51892               var cmdLen = pbf.readVarint();
51893               cmd = cmdLen & 0x7;
51894               length = cmdLen >> 3;
51895             }
51896
51897             length--;
51898
51899             if (cmd === 1 || cmd === 2) {
51900               x += pbf.readSVarint();
51901               y += pbf.readSVarint();
51902
51903               if (cmd === 1) {
51904                 // moveTo
51905                 if (line) lines.push(line);
51906                 line = [];
51907               }
51908
51909               line.push(new pointGeometry(x, y));
51910             } else if (cmd === 7) {
51911               // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90
51912               if (line) {
51913                 line.push(line[0].clone()); // closePolygon
51914               }
51915             } else {
51916               throw new Error('unknown command ' + cmd);
51917             }
51918           }
51919
51920           if (line) lines.push(line);
51921           return lines;
51922         };
51923
51924         VectorTileFeature.prototype.bbox = function () {
51925           var pbf = this._pbf;
51926           pbf.pos = this._geometry;
51927           var end = pbf.readVarint() + pbf.pos,
51928               cmd = 1,
51929               length = 0,
51930               x = 0,
51931               y = 0,
51932               x1 = Infinity,
51933               x2 = -Infinity,
51934               y1 = Infinity,
51935               y2 = -Infinity;
51936
51937           while (pbf.pos < end) {
51938             if (length <= 0) {
51939               var cmdLen = pbf.readVarint();
51940               cmd = cmdLen & 0x7;
51941               length = cmdLen >> 3;
51942             }
51943
51944             length--;
51945
51946             if (cmd === 1 || cmd === 2) {
51947               x += pbf.readSVarint();
51948               y += pbf.readSVarint();
51949               if (x < x1) x1 = x;
51950               if (x > x2) x2 = x;
51951               if (y < y1) y1 = y;
51952               if (y > y2) y2 = y;
51953             } else if (cmd !== 7) {
51954               throw new Error('unknown command ' + cmd);
51955             }
51956           }
51957
51958           return [x1, y1, x2, y2];
51959         };
51960
51961         VectorTileFeature.prototype.toGeoJSON = function (x, y, z) {
51962           var size = this.extent * Math.pow(2, z),
51963               x0 = this.extent * x,
51964               y0 = this.extent * y,
51965               coords = this.loadGeometry(),
51966               type = VectorTileFeature.types[this.type],
51967               i,
51968               j;
51969
51970           function project(line) {
51971             for (var j = 0; j < line.length; j++) {
51972               var p = line[j],
51973                   y2 = 180 - (p.y + y0) * 360 / size;
51974               line[j] = [(p.x + x0) * 360 / size - 180, 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90];
51975             }
51976           }
51977
51978           switch (this.type) {
51979             case 1:
51980               var points = [];
51981
51982               for (i = 0; i < coords.length; i++) {
51983                 points[i] = coords[i][0];
51984               }
51985
51986               coords = points;
51987               project(coords);
51988               break;
51989
51990             case 2:
51991               for (i = 0; i < coords.length; i++) {
51992                 project(coords[i]);
51993               }
51994
51995               break;
51996
51997             case 3:
51998               coords = classifyRings(coords);
51999
52000               for (i = 0; i < coords.length; i++) {
52001                 for (j = 0; j < coords[i].length; j++) {
52002                   project(coords[i][j]);
52003                 }
52004               }
52005
52006               break;
52007           }
52008
52009           if (coords.length === 1) {
52010             coords = coords[0];
52011           } else {
52012             type = 'Multi' + type;
52013           }
52014
52015           var result = {
52016             type: "Feature",
52017             geometry: {
52018               type: type,
52019               coordinates: coords
52020             },
52021             properties: this.properties
52022           };
52023
52024           if ('id' in this) {
52025             result.id = this.id;
52026           }
52027
52028           return result;
52029         }; // classifies an array of rings into polygons with outer rings and holes
52030
52031
52032         function classifyRings(rings) {
52033           var len = rings.length;
52034           if (len <= 1) return [rings];
52035           var polygons = [],
52036               polygon,
52037               ccw;
52038
52039           for (var i = 0; i < len; i++) {
52040             var area = signedArea$1(rings[i]);
52041             if (area === 0) continue;
52042             if (ccw === undefined) ccw = area < 0;
52043
52044             if (ccw === area < 0) {
52045               if (polygon) polygons.push(polygon);
52046               polygon = [rings[i]];
52047             } else {
52048               polygon.push(rings[i]);
52049             }
52050           }
52051
52052           if (polygon) polygons.push(polygon);
52053           return polygons;
52054         }
52055
52056         function signedArea$1(ring) {
52057           var sum = 0;
52058
52059           for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
52060             p1 = ring[i];
52061             p2 = ring[j];
52062             sum += (p2.x - p1.x) * (p1.y + p2.y);
52063           }
52064
52065           return sum;
52066         }
52067
52068         var vectortilelayer = VectorTileLayer;
52069
52070         function VectorTileLayer(pbf, end) {
52071           // Public
52072           this.version = 1;
52073           this.name = null;
52074           this.extent = 4096;
52075           this.length = 0; // Private
52076
52077           this._pbf = pbf;
52078           this._keys = [];
52079           this._values = [];
52080           this._features = [];
52081           pbf.readFields(readLayer, this, end);
52082           this.length = this._features.length;
52083         }
52084
52085         function readLayer(tag, layer, pbf) {
52086           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));
52087         }
52088
52089         function readValueMessage(pbf) {
52090           var value = null,
52091               end = pbf.readVarint() + pbf.pos;
52092
52093           while (pbf.pos < end) {
52094             var tag = pbf.readVarint() >> 3;
52095             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;
52096           }
52097
52098           return value;
52099         } // return feature `i` from this layer as a `VectorTileFeature`
52100
52101
52102         VectorTileLayer.prototype.feature = function (i) {
52103           if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds');
52104           this._pbf.pos = this._features[i];
52105
52106           var end = this._pbf.readVarint() + this._pbf.pos;
52107
52108           return new vectortilefeature(this._pbf, end, this.extent, this._keys, this._values);
52109         };
52110
52111         var vectortile = VectorTile;
52112
52113         function VectorTile(pbf, end) {
52114           this.layers = pbf.readFields(readTile, {}, end);
52115         }
52116
52117         function readTile(tag, layers, pbf) {
52118           if (tag === 3) {
52119             var layer = new vectortilelayer(pbf, pbf.readVarint() + pbf.pos);
52120             if (layer.length) layers[layer.name] = layer;
52121           }
52122         }
52123
52124         var VectorTile$1 = vectortile;
52125         var VectorTileFeature$1 = vectortilefeature;
52126         var VectorTileLayer$1 = vectortilelayer;
52127         var vectorTile = {
52128           VectorTile: VectorTile$1,
52129           VectorTileFeature: VectorTileFeature$1,
52130           VectorTileLayer: VectorTileLayer$1
52131         };
52132
52133         var tiler$7 = utilTiler().tileSize(512).margin(1);
52134         var dispatch$8 = dispatch('loadedData');
52135
52136         var _vtCache;
52137
52138         function abortRequest$7(controller) {
52139           controller.abort();
52140         }
52141
52142         function vtToGeoJSON(data, tile, mergeCache) {
52143           var vectorTile$1 = new vectorTile.VectorTile(new pbf(data));
52144           var layers = Object.keys(vectorTile$1.layers);
52145
52146           if (!Array.isArray(layers)) {
52147             layers = [layers];
52148           }
52149
52150           var features = [];
52151           layers.forEach(function (layerID) {
52152             var layer = vectorTile$1.layers[layerID];
52153
52154             if (layer) {
52155               for (var i = 0; i < layer.length; i++) {
52156                 var feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
52157                 var geometry = feature.geometry; // Treat all Polygons as MultiPolygons
52158
52159                 if (geometry.type === 'Polygon') {
52160                   geometry.type = 'MultiPolygon';
52161                   geometry.coordinates = [geometry.coordinates];
52162                 }
52163
52164                 var isClipped = false; // Clip to tile bounds
52165
52166                 if (geometry.type === 'MultiPolygon') {
52167                   var featureClip = turf_bboxClip(feature, tile.extent.rectangle());
52168
52169                   if (!fastDeepEqual(feature.geometry, featureClip.geometry)) {
52170                     // feature = featureClip;
52171                     isClipped = true;
52172                   }
52173
52174                   if (!feature.geometry.coordinates.length) continue; // not actually on this tile
52175
52176                   if (!feature.geometry.coordinates[0].length) continue; // not actually on this tile
52177                 } // Generate some unique IDs and add some metadata
52178
52179
52180                 var featurehash = utilHashcode(fastJsonStableStringify(feature));
52181                 var propertyhash = utilHashcode(fastJsonStableStringify(feature.properties || {}));
52182                 feature.__layerID__ = layerID.replace(/[^_a-zA-Z0-9\-]/g, '_');
52183                 feature.__featurehash__ = featurehash;
52184                 feature.__propertyhash__ = propertyhash;
52185                 features.push(feature); // Clipped Polygons at same zoom with identical properties can get merged
52186
52187                 if (isClipped && geometry.type === 'MultiPolygon') {
52188                   var merged = mergeCache[propertyhash];
52189
52190                   if (merged && merged.length) {
52191                     var other = merged[0];
52192                     var coords = union(feature.geometry.coordinates, other.geometry.coordinates);
52193
52194                     if (!coords || !coords.length) {
52195                       continue; // something failed in martinez union
52196                     }
52197
52198                     merged.push(feature);
52199
52200                     for (var j = 0; j < merged.length; j++) {
52201                       // all these features get...
52202                       merged[j].geometry.coordinates = coords; // same coords
52203
52204                       merged[j].__featurehash__ = featurehash; // same hash, so deduplication works
52205                     }
52206                   } else {
52207                     mergeCache[propertyhash] = [feature];
52208                   }
52209                 }
52210               }
52211             }
52212           });
52213           return features;
52214         }
52215
52216         function loadTile(source, tile) {
52217           if (source.loaded[tile.id] || source.inflight[tile.id]) return;
52218           var url = source.template.replace('{x}', tile.xyz[0]).replace('{y}', tile.xyz[1]) // TMS-flipped y coordinate
52219           .replace(/\{[t-]y\}/, Math.pow(2, tile.xyz[2]) - tile.xyz[1] - 1).replace(/\{z(oom)?\}/, tile.xyz[2]).replace(/\{switch:([^}]+)\}/, function (s, r) {
52220             var subdomains = r.split(',');
52221             return subdomains[(tile.xyz[0] + tile.xyz[1]) % subdomains.length];
52222           });
52223           var controller = new AbortController();
52224           source.inflight[tile.id] = controller;
52225           fetch(url, {
52226             signal: controller.signal
52227           }).then(function (response) {
52228             if (!response.ok) {
52229               throw new Error(response.status + ' ' + response.statusText);
52230             }
52231
52232             source.loaded[tile.id] = [];
52233             delete source.inflight[tile.id];
52234             return response.arrayBuffer();
52235           }).then(function (data) {
52236             if (!data) {
52237               throw new Error('No Data');
52238             }
52239
52240             var z = tile.xyz[2];
52241
52242             if (!source.canMerge[z]) {
52243               source.canMerge[z] = {}; // initialize mergeCache
52244             }
52245
52246             source.loaded[tile.id] = vtToGeoJSON(data, tile, source.canMerge[z]);
52247             dispatch$8.call('loadedData');
52248           })["catch"](function () {
52249             source.loaded[tile.id] = [];
52250             delete source.inflight[tile.id];
52251           });
52252         }
52253
52254         var serviceVectorTile = {
52255           init: function init() {
52256             if (!_vtCache) {
52257               this.reset();
52258             }
52259
52260             this.event = utilRebind(this, dispatch$8, 'on');
52261           },
52262           reset: function reset() {
52263             for (var sourceID in _vtCache) {
52264               var source = _vtCache[sourceID];
52265
52266               if (source && source.inflight) {
52267                 Object.values(source.inflight).forEach(abortRequest$7);
52268               }
52269             }
52270
52271             _vtCache = {};
52272           },
52273           addSource: function addSource(sourceID, template) {
52274             _vtCache[sourceID] = {
52275               template: template,
52276               inflight: {},
52277               loaded: {},
52278               canMerge: {}
52279             };
52280             return _vtCache[sourceID];
52281           },
52282           data: function data(sourceID, projection) {
52283             var source = _vtCache[sourceID];
52284             if (!source) return [];
52285             var tiles = tiler$7.getTiles(projection);
52286             var seen = {};
52287             var results = [];
52288
52289             for (var i = 0; i < tiles.length; i++) {
52290               var features = source.loaded[tiles[i].id];
52291               if (!features || !features.length) continue;
52292
52293               for (var j = 0; j < features.length; j++) {
52294                 var feature = features[j];
52295                 var hash = feature.__featurehash__;
52296                 if (seen[hash]) continue;
52297                 seen[hash] = true; // return a shallow copy, because the hash may change
52298                 // later if this feature gets merged with another
52299
52300                 results.push(Object.assign({}, feature)); // shallow copy
52301               }
52302             }
52303
52304             return results;
52305           },
52306           loadTiles: function loadTiles(sourceID, template, projection) {
52307             var source = _vtCache[sourceID];
52308
52309             if (!source) {
52310               source = this.addSource(sourceID, template);
52311             }
52312
52313             var tiles = tiler$7.getTiles(projection); // abort inflight requests that are no longer needed
52314
52315             Object.keys(source.inflight).forEach(function (k) {
52316               var wanted = tiles.find(function (tile) {
52317                 return k === tile.id;
52318               });
52319
52320               if (!wanted) {
52321                 abortRequest$7(source.inflight[k]);
52322                 delete source.inflight[k];
52323               }
52324             });
52325             tiles.forEach(function (tile) {
52326               loadTile(source, tile);
52327             });
52328           },
52329           cache: function cache() {
52330             return _vtCache;
52331           }
52332         };
52333
52334         var apibase$3 = 'https://www.wikidata.org/w/api.php?';
52335         var _wikidataCache = {};
52336         var serviceWikidata = {
52337           init: function init() {},
52338           reset: function reset() {
52339             _wikidataCache = {};
52340           },
52341           // Search for Wikidata items matching the query
52342           itemsForSearchQuery: function itemsForSearchQuery(query, callback) {
52343             if (!query) {
52344               if (callback) callback('No query', {});
52345               return;
52346             }
52347
52348             var lang = this.languagesToQuery()[0];
52349             var url = apibase$3 + utilQsString({
52350               action: 'wbsearchentities',
52351               format: 'json',
52352               formatversion: 2,
52353               search: query,
52354               type: 'item',
52355               // the language to search
52356               language: lang,
52357               // the language for the label and description in the result
52358               uselang: lang,
52359               limit: 10,
52360               origin: '*'
52361             });
52362             d3_json(url).then(function (result) {
52363               if (result && result.error) {
52364                 throw new Error(result.error);
52365               }
52366
52367               if (callback) callback(null, result.search || {});
52368             })["catch"](function (err) {
52369               if (callback) callback(err.message, {});
52370             });
52371           },
52372           // Given a Wikipedia language and article title,
52373           // return an array of corresponding Wikidata entities.
52374           itemsByTitle: function itemsByTitle(lang, title, callback) {
52375             if (!title) {
52376               if (callback) callback('No title', {});
52377               return;
52378             }
52379
52380             lang = lang || 'en';
52381             var url = apibase$3 + utilQsString({
52382               action: 'wbgetentities',
52383               format: 'json',
52384               formatversion: 2,
52385               sites: lang.replace(/-/g, '_') + 'wiki',
52386               titles: title,
52387               languages: 'en',
52388               // shrink response by filtering to one language
52389               origin: '*'
52390             });
52391             d3_json(url).then(function (result) {
52392               if (result && result.error) {
52393                 throw new Error(result.error);
52394               }
52395
52396               if (callback) callback(null, result.entities || {});
52397             })["catch"](function (err) {
52398               if (callback) callback(err.message, {});
52399             });
52400           },
52401           languagesToQuery: function languagesToQuery() {
52402             return _mainLocalizer.localeCodes().map(function (code) {
52403               return code.toLowerCase();
52404             }).filter(function (code) {
52405               // HACK: en-us isn't a wikidata language. We should really be filtering by
52406               // the languages known to be supported by wikidata.
52407               return code !== 'en-us';
52408             });
52409           },
52410           entityByQID: function entityByQID(qid, callback) {
52411             if (!qid) {
52412               callback('No qid', {});
52413               return;
52414             }
52415
52416             if (_wikidataCache[qid]) {
52417               if (callback) callback(null, _wikidataCache[qid]);
52418               return;
52419             }
52420
52421             var langs = this.languagesToQuery();
52422             var url = apibase$3 + utilQsString({
52423               action: 'wbgetentities',
52424               format: 'json',
52425               formatversion: 2,
52426               ids: qid,
52427               props: 'labels|descriptions|claims|sitelinks',
52428               sitefilter: langs.map(function (d) {
52429                 return d + 'wiki';
52430               }).join('|'),
52431               languages: langs.join('|'),
52432               languagefallback: 1,
52433               origin: '*'
52434             });
52435             d3_json(url).then(function (result) {
52436               if (result && result.error) {
52437                 throw new Error(result.error);
52438               }
52439
52440               if (callback) callback(null, result.entities[qid] || {});
52441             })["catch"](function (err) {
52442               if (callback) callback(err.message, {});
52443             });
52444           },
52445           // Pass `params` object of the form:
52446           // {
52447           //   qid: 'string'      // brand wikidata  (e.g. 'Q37158')
52448           // }
52449           //
52450           // Get an result object used to display tag documentation
52451           // {
52452           //   title:        'string',
52453           //   description:  'string',
52454           //   editURL:      'string',
52455           //   imageURL:     'string',
52456           //   wiki:         { title: 'string', text: 'string', url: 'string' }
52457           // }
52458           //
52459           getDocs: function getDocs(params, callback) {
52460             var langs = this.languagesToQuery();
52461             this.entityByQID(params.qid, function (err, entity) {
52462               if (err || !entity) {
52463                 callback(err || 'No entity');
52464                 return;
52465               }
52466
52467               var i;
52468               var description;
52469
52470               for (i in langs) {
52471                 var code = langs[i];
52472
52473                 if (entity.descriptions[code] && entity.descriptions[code].language === code) {
52474                   description = entity.descriptions[code];
52475                   break;
52476                 }
52477               }
52478
52479               if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result
52480
52481               var result = {
52482                 title: entity.id,
52483                 description: description ? description.value : '',
52484                 descriptionLocaleCode: description ? description.language : '',
52485                 editURL: 'https://www.wikidata.org/wiki/' + entity.id
52486               }; // add image
52487
52488               if (entity.claims) {
52489                 var imageroot = 'https://commons.wikimedia.org/w/index.php';
52490                 var props = ['P154', 'P18']; // logo image, image
52491
52492                 var prop, image;
52493
52494                 for (i = 0; i < props.length; i++) {
52495                   prop = entity.claims[props[i]];
52496
52497                   if (prop && Object.keys(prop).length > 0) {
52498                     image = prop[Object.keys(prop)[0]].mainsnak.datavalue.value;
52499
52500                     if (image) {
52501                       result.imageURL = imageroot + '?' + utilQsString({
52502                         title: 'Special:Redirect/file/' + image,
52503                         width: 400
52504                       });
52505                       break;
52506                     }
52507                   }
52508                 }
52509               }
52510
52511               if (entity.sitelinks) {
52512                 var englishLocale = _mainLocalizer.languageCode().toLowerCase() === 'en'; // must be one of these that we requested..
52513
52514                 for (i = 0; i < langs.length; i++) {
52515                   // check each, in order of preference
52516                   var w = langs[i] + 'wiki';
52517
52518                   if (entity.sitelinks[w]) {
52519                     var title = entity.sitelinks[w].title;
52520                     var tKey = 'inspector.wiki_reference';
52521
52522                     if (!englishLocale && langs[i] === 'en') {
52523                       // user's locale isn't English but
52524                       tKey = 'inspector.wiki_en_reference'; // we are sending them to enwiki anyway..
52525                     }
52526
52527                     result.wiki = {
52528                       title: title,
52529                       text: tKey,
52530                       url: 'https://' + langs[i] + '.wikipedia.org/wiki/' + title.replace(/ /g, '_')
52531                     };
52532                     break;
52533                   }
52534                 }
52535               }
52536
52537               callback(null, result);
52538             });
52539           }
52540         };
52541
52542         var endpoint = 'https://en.wikipedia.org/w/api.php?';
52543         var serviceWikipedia = {
52544           init: function init() {},
52545           reset: function reset() {},
52546           search: function search(lang, query, callback) {
52547             if (!query) {
52548               if (callback) callback('No Query', []);
52549               return;
52550             }
52551
52552             lang = lang || 'en';
52553             var url = endpoint.replace('en', lang) + utilQsString({
52554               action: 'query',
52555               list: 'search',
52556               srlimit: '10',
52557               srinfo: 'suggestion',
52558               format: 'json',
52559               origin: '*',
52560               srsearch: query
52561             });
52562             d3_json(url).then(function (result) {
52563               if (result && result.error) {
52564                 throw new Error(result.error);
52565               } else if (!result || !result.query || !result.query.search) {
52566                 throw new Error('No Results');
52567               }
52568
52569               if (callback) {
52570                 var titles = result.query.search.map(function (d) {
52571                   return d.title;
52572                 });
52573                 callback(null, titles);
52574               }
52575             })["catch"](function (err) {
52576               if (callback) callback(err, []);
52577             });
52578           },
52579           suggestions: function suggestions(lang, query, callback) {
52580             if (!query) {
52581               if (callback) callback('', []);
52582               return;
52583             }
52584
52585             lang = lang || 'en';
52586             var url = endpoint.replace('en', lang) + utilQsString({
52587               action: 'opensearch',
52588               namespace: 0,
52589               suggest: '',
52590               format: 'json',
52591               origin: '*',
52592               search: query
52593             });
52594             d3_json(url).then(function (result) {
52595               if (result && result.error) {
52596                 throw new Error(result.error);
52597               } else if (!result || result.length < 2) {
52598                 throw new Error('No Results');
52599               }
52600
52601               if (callback) callback(null, result[1] || []);
52602             })["catch"](function (err) {
52603               if (callback) callback(err.message, []);
52604             });
52605           },
52606           translations: function translations(lang, title, callback) {
52607             if (!title) {
52608               if (callback) callback('No Title');
52609               return;
52610             }
52611
52612             var url = endpoint.replace('en', lang) + utilQsString({
52613               action: 'query',
52614               prop: 'langlinks',
52615               format: 'json',
52616               origin: '*',
52617               lllimit: 500,
52618               titles: title
52619             });
52620             d3_json(url).then(function (result) {
52621               if (result && result.error) {
52622                 throw new Error(result.error);
52623               } else if (!result || !result.query || !result.query.pages) {
52624                 throw new Error('No Results');
52625               }
52626
52627               if (callback) {
52628                 var list = result.query.pages[Object.keys(result.query.pages)[0]];
52629                 var translations = {};
52630
52631                 if (list && list.langlinks) {
52632                   list.langlinks.forEach(function (d) {
52633                     translations[d.lang] = d['*'];
52634                   });
52635                 }
52636
52637                 callback(null, translations);
52638               }
52639             })["catch"](function (err) {
52640               if (callback) callback(err.message);
52641             });
52642           }
52643         };
52644
52645         var services = {
52646           geocoder: serviceNominatim,
52647           keepRight: serviceKeepRight,
52648           improveOSM: serviceImproveOSM,
52649           osmose: serviceOsmose,
52650           mapillary: serviceMapillary,
52651           openstreetcam: serviceOpenstreetcam,
52652           osm: serviceOsm,
52653           osmWikibase: serviceOsmWikibase,
52654           maprules: serviceMapRules,
52655           streetside: serviceStreetside,
52656           taginfo: serviceTaginfo,
52657           vectorTile: serviceVectorTile,
52658           wikidata: serviceWikidata,
52659           wikipedia: serviceWikipedia
52660         };
52661
52662         function svgIcon(name, svgklass, useklass) {
52663           return function drawIcon(selection) {
52664             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);
52665           };
52666         }
52667
52668         function uiNoteComments() {
52669           var _note;
52670
52671           function noteComments(selection) {
52672             if (_note.isNew()) return; // don't draw .comments-container
52673
52674             var comments = selection.selectAll('.comments-container').data([0]);
52675             comments = comments.enter().append('div').attr('class', 'comments-container').merge(comments);
52676             var commentEnter = comments.selectAll('.comment').data(_note.comments).enter().append('div').attr('class', 'comment');
52677             commentEnter.append('div').attr('class', function (d) {
52678               return 'comment-avatar user-' + d.uid;
52679             }).call(svgIcon('#iD-icon-avatar', 'comment-avatar-icon'));
52680             var mainEnter = commentEnter.append('div').attr('class', 'comment-main');
52681             var metadataEnter = mainEnter.append('div').attr('class', 'comment-metadata');
52682             metadataEnter.append('div').attr('class', 'comment-author').each(function (d) {
52683               var selection = select(this);
52684               var osm = services.osm;
52685
52686               if (osm && d.user) {
52687                 selection = selection.append('a').attr('class', 'comment-author-link').attr('href', osm.userURL(d.user)).attr('target', '_blank');
52688               }
52689
52690               selection.html(function (d) {
52691                 return d.user || _t.html('note.anonymous');
52692               });
52693             });
52694             metadataEnter.append('div').attr('class', 'comment-date').html(function (d) {
52695               return _t('note.status.' + d.action, {
52696                 when: localeDateString(d.date)
52697               });
52698             });
52699             mainEnter.append('div').attr('class', 'comment-text').html(function (d) {
52700               return d.html;
52701             }).selectAll('a').attr('rel', 'noopener nofollow').attr('target', '_blank');
52702             comments.call(replaceAvatars);
52703           }
52704
52705           function replaceAvatars(selection) {
52706             var showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
52707             var osm = services.osm;
52708             if (showThirdPartyIcons !== 'true' || !osm) return;
52709             var uids = {}; // gather uids in the comment thread
52710
52711             _note.comments.forEach(function (d) {
52712               if (d.uid) uids[d.uid] = true;
52713             });
52714
52715             Object.keys(uids).forEach(function (uid) {
52716               osm.loadUser(uid, function (err, user) {
52717                 if (!user || !user.image_url) return;
52718                 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);
52719               });
52720             });
52721           }
52722
52723           function localeDateString(s) {
52724             if (!s) return null;
52725             var options = {
52726               day: 'numeric',
52727               month: 'short',
52728               year: 'numeric'
52729             };
52730             s = s.replace(/-/g, '/'); // fix browser-specific Date() issues
52731
52732             var d = new Date(s);
52733             if (isNaN(d.getTime())) return null;
52734             return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
52735           }
52736
52737           noteComments.note = function (val) {
52738             if (!arguments.length) return _note;
52739             _note = val;
52740             return noteComments;
52741           };
52742
52743           return noteComments;
52744         }
52745
52746         function uiNoteHeader() {
52747           var _note;
52748
52749           function noteHeader(selection) {
52750             var header = selection.selectAll('.note-header').data(_note ? [_note] : [], function (d) {
52751               return d.status + d.id;
52752             });
52753             header.exit().remove();
52754             var headerEnter = header.enter().append('div').attr('class', 'note-header');
52755             var iconEnter = headerEnter.append('div').attr('class', function (d) {
52756               return 'note-header-icon ' + d.status;
52757             }).classed('new', function (d) {
52758               return d.id < 0;
52759             });
52760             iconEnter.append('div').attr('class', 'preset-icon-28').call(svgIcon('#iD-icon-note', 'note-fill'));
52761             iconEnter.each(function (d) {
52762               var statusIcon = '#iD-icon-' + (d.id < 0 ? 'plus' : d.status === 'open' ? 'close' : 'apply');
52763               iconEnter.append('div').attr('class', 'note-icon-annotation').call(svgIcon(statusIcon, 'icon-annotation'));
52764             });
52765             headerEnter.append('div').attr('class', 'note-header-label').html(function (d) {
52766               if (_note.isNew()) {
52767                 return _t('note.new');
52768               }
52769
52770               return _t('note.note') + ' ' + d.id + ' ' + (d.status === 'closed' ? _t('note.closed') : '');
52771             });
52772           }
52773
52774           noteHeader.note = function (val) {
52775             if (!arguments.length) return _note;
52776             _note = val;
52777             return noteHeader;
52778           };
52779
52780           return noteHeader;
52781         }
52782
52783         function uiNoteReport() {
52784           var _note;
52785
52786           function noteReport(selection) {
52787             var url;
52788
52789             if (services.osm && _note instanceof osmNote && !_note.isNew()) {
52790               url = services.osm.noteReportURL(_note);
52791             }
52792
52793             var link = selection.selectAll('.note-report').data(url ? [url] : []); // exit
52794
52795             link.exit().remove(); // enter
52796
52797             var linkEnter = link.enter().append('a').attr('class', 'note-report').attr('target', '_blank').attr('href', function (d) {
52798               return d;
52799             }).call(svgIcon('#iD-icon-out-link', 'inline'));
52800             linkEnter.append('span').html(_t.html('note.report'));
52801           }
52802
52803           noteReport.note = function (val) {
52804             if (!arguments.length) return _note;
52805             _note = val;
52806             return noteReport;
52807           };
52808
52809           return noteReport;
52810         }
52811
52812         function uiViewOnOSM(context) {
52813           var _what; // an osmEntity or osmNote
52814
52815
52816           function viewOnOSM(selection) {
52817             var url;
52818
52819             if (_what instanceof osmEntity) {
52820               url = context.connection().entityURL(_what);
52821             } else if (_what instanceof osmNote) {
52822               url = context.connection().noteURL(_what);
52823             }
52824
52825             var data = !_what || _what.isNew() ? [] : [_what];
52826             var link = selection.selectAll('.view-on-osm').data(data, function (d) {
52827               return d.id;
52828             }); // exit
52829
52830             link.exit().remove(); // enter
52831
52832             var linkEnter = link.enter().append('a').attr('class', 'view-on-osm').attr('target', '_blank').attr('href', url).call(svgIcon('#iD-icon-out-link', 'inline'));
52833             linkEnter.append('span').html(_t.html('inspector.view_on_osm'));
52834           }
52835
52836           viewOnOSM.what = function (_) {
52837             if (!arguments.length) return _what;
52838             _what = _;
52839             return viewOnOSM;
52840           };
52841
52842           return viewOnOSM;
52843         }
52844
52845         function uiNoteEditor(context) {
52846           var dispatch$1 = dispatch('change');
52847           var noteComments = uiNoteComments();
52848           var noteHeader = uiNoteHeader(); // var formFields = uiFormFields(context);
52849
52850           var _note;
52851
52852           var _newNote; // var _fieldsArr;
52853
52854
52855           function noteEditor(selection) {
52856             var header = selection.selectAll('.header').data([0]);
52857             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
52858             headerEnter.append('button').attr('class', 'close').on('click', function () {
52859               context.enter(modeBrowse(context));
52860             }).call(svgIcon('#iD-icon-close'));
52861             headerEnter.append('h3').html(_t.html('note.title'));
52862             var body = selection.selectAll('.body').data([0]);
52863             body = body.enter().append('div').attr('class', 'body').merge(body);
52864             var editor = body.selectAll('.note-editor').data([0]);
52865             editor.enter().append('div').attr('class', 'modal-section note-editor').merge(editor).call(noteHeader.note(_note)).call(noteComments.note(_note)).call(noteSaveSection);
52866             var footer = selection.selectAll('.footer').data([0]);
52867             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
52868
52869             var osm = services.osm;
52870
52871             if (osm) {
52872               osm.on('change.note-save', function () {
52873                 selection.call(noteEditor);
52874               });
52875             }
52876           }
52877
52878           function noteSaveSection(selection) {
52879             var isSelected = _note && _note.id === context.selectedNoteID();
52880
52881             var noteSave = selection.selectAll('.note-save').data(isSelected ? [_note] : [], function (d) {
52882               return d.status + d.id;
52883             }); // exit
52884
52885             noteSave.exit().remove(); // enter
52886
52887             var noteSaveEnter = noteSave.enter().append('div').attr('class', 'note-save save-section cf'); // // if new note, show categories to pick from
52888             // if (_note.isNew()) {
52889             //     var presets = presetManager;
52890             //     // NOTE: this key isn't a age and therefore there is no documentation (yet)
52891             //     _fieldsArr = [
52892             //         uiField(context, presets.field('category'), null, { show: true, revert: false }),
52893             //     ];
52894             //     _fieldsArr.forEach(function(field) {
52895             //         field
52896             //             .on('change', changeCategory);
52897             //     });
52898             //     noteSaveEnter
52899             //         .append('div')
52900             //         .attr('class', 'note-category')
52901             //         .call(formFields.fieldsArr(_fieldsArr));
52902             // }
52903             // function changeCategory() {
52904             //     // NOTE: perhaps there is a better way to get value
52905             //     var val = context.container().select('input[name=\'category\']:checked').property('__data__') || undefined;
52906             //     // store the unsaved category with the note itself
52907             //     _note = _note.update({ newCategory: val });
52908             //     var osm = services.osm;
52909             //     if (osm) {
52910             //         osm.replaceNote(_note);  // update note cache
52911             //     }
52912             //     noteSave
52913             //         .call(noteSaveButtons);
52914             // }
52915
52916             noteSaveEnter.append('h4').attr('class', '.note-save-header').html(function () {
52917               return _note.isNew() ? _t('note.newDescription') : _t('note.newComment');
52918             });
52919             var commentTextarea = noteSaveEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('note.inputPlaceholder')).attr('maxlength', 1000).property('value', function (d) {
52920               return d.newComment;
52921             }).call(utilNoAuto).on('keydown.note-input', keydown).on('input.note-input', changeInput).on('blur.note-input', changeInput);
52922
52923             if (!commentTextarea.empty() && _newNote) {
52924               // autofocus the comment field for new notes
52925               commentTextarea.node().focus();
52926             } // update
52927
52928
52929             noteSave = noteSaveEnter.merge(noteSave).call(userDetails).call(noteSaveButtons); // fast submit if user presses cmd+enter
52930
52931             function keydown(d3_event) {
52932               if (!(d3_event.keyCode === 13 && // ↩ Return
52933               d3_event.metaKey)) return;
52934               var osm = services.osm;
52935               if (!osm) return;
52936               var hasAuth = osm.authenticated();
52937               if (!hasAuth) return;
52938               if (!_note.newComment) return;
52939               d3_event.preventDefault();
52940               select(this).on('keydown.note-input', null); // focus on button and submit
52941
52942               window.setTimeout(function () {
52943                 if (_note.isNew()) {
52944                   noteSave.selectAll('.save-button').node().focus();
52945                   clickSave();
52946                 } else {
52947                   noteSave.selectAll('.comment-button').node().focus();
52948                   clickComment();
52949                 }
52950               }, 10);
52951             }
52952
52953             function changeInput() {
52954               var input = select(this);
52955               var val = input.property('value').trim() || undefined; // store the unsaved comment with the note itself
52956
52957               _note = _note.update({
52958                 newComment: val
52959               });
52960               var osm = services.osm;
52961
52962               if (osm) {
52963                 osm.replaceNote(_note); // update note cache
52964               }
52965
52966               noteSave.call(noteSaveButtons);
52967             }
52968           }
52969
52970           function userDetails(selection) {
52971             var detailSection = selection.selectAll('.detail-section').data([0]);
52972             detailSection = detailSection.enter().append('div').attr('class', 'detail-section').merge(detailSection);
52973             var osm = services.osm;
52974             if (!osm) return; // Add warning if user is not logged in
52975
52976             var hasAuth = osm.authenticated();
52977             var authWarning = detailSection.selectAll('.auth-warning').data(hasAuth ? [] : [0]);
52978             authWarning.exit().transition().duration(200).style('opacity', 0).remove();
52979             var authEnter = authWarning.enter().insert('div', '.tag-reference-body').attr('class', 'field-warning auth-warning').style('opacity', 0);
52980             authEnter.call(svgIcon('#iD-icon-alert', 'inline'));
52981             authEnter.append('span').html(_t.html('note.login'));
52982             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) {
52983               d3_event.preventDefault();
52984               osm.authenticate();
52985             });
52986             authEnter.transition().duration(200).style('opacity', 1);
52987             var prose = detailSection.selectAll('.note-save-prose').data(hasAuth ? [0] : []);
52988             prose.exit().remove();
52989             prose = prose.enter().append('p').attr('class', 'note-save-prose').html(_t.html('note.upload_explanation')).merge(prose);
52990             osm.userDetails(function (err, user) {
52991               if (err) return;
52992               var userLink = select(document.createElement('div'));
52993
52994               if (user.image_url) {
52995                 userLink.append('img').attr('src', user.image_url).attr('class', 'icon pre-text user-icon');
52996               }
52997
52998               userLink.append('a').attr('class', 'user-info').html(user.display_name).attr('href', osm.userURL(user.display_name)).attr('target', '_blank');
52999               prose.html(_t.html('note.upload_explanation_with_user', {
53000                 user: userLink.html()
53001               }));
53002             });
53003           }
53004
53005           function noteSaveButtons(selection) {
53006             var osm = services.osm;
53007             var hasAuth = osm && osm.authenticated();
53008
53009             var isSelected = _note && _note.id === context.selectedNoteID();
53010
53011             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_note] : [], function (d) {
53012               return d.status + d.id;
53013             }); // exit
53014
53015             buttonSection.exit().remove(); // enter
53016
53017             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
53018
53019             if (_note.isNew()) {
53020               buttonEnter.append('button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
53021               buttonEnter.append('button').attr('class', 'button save-button action').html(_t.html('note.save'));
53022             } else {
53023               buttonEnter.append('button').attr('class', 'button status-button action');
53024               buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('note.comment'));
53025             } // update
53026
53027
53028             buttonSection = buttonSection.merge(buttonEnter);
53029             buttonSection.select('.cancel-button') // select and propagate data
53030             .on('click.cancel', clickCancel);
53031             buttonSection.select('.save-button') // select and propagate data
53032             .attr('disabled', isSaveDisabled).on('click.save', clickSave);
53033             buttonSection.select('.status-button') // select and propagate data
53034             .attr('disabled', hasAuth ? null : true).html(function (d) {
53035               var action = d.status === 'open' ? 'close' : 'open';
53036               var andComment = d.newComment ? '_comment' : '';
53037               return _t('note.' + action + andComment);
53038             }).on('click.status', clickStatus);
53039             buttonSection.select('.comment-button') // select and propagate data
53040             .attr('disabled', isSaveDisabled).on('click.comment', clickComment);
53041
53042             function isSaveDisabled(d) {
53043               return hasAuth && d.status === 'open' && d.newComment ? null : true;
53044             }
53045           }
53046
53047           function clickCancel(d3_event, d) {
53048             this.blur(); // avoid keeping focus on the button - #4641
53049
53050             var osm = services.osm;
53051
53052             if (osm) {
53053               osm.removeNote(d);
53054             }
53055
53056             context.enter(modeBrowse(context));
53057             dispatch$1.call('change');
53058           }
53059
53060           function clickSave(d3_event, d) {
53061             this.blur(); // avoid keeping focus on the button - #4641
53062
53063             var osm = services.osm;
53064
53065             if (osm) {
53066               osm.postNoteCreate(d, function (err, note) {
53067                 dispatch$1.call('change', note);
53068               });
53069             }
53070           }
53071
53072           function clickStatus(d3_event, d) {
53073             this.blur(); // avoid keeping focus on the button - #4641
53074
53075             var osm = services.osm;
53076
53077             if (osm) {
53078               var setStatus = d.status === 'open' ? 'closed' : 'open';
53079               osm.postNoteUpdate(d, setStatus, function (err, note) {
53080                 dispatch$1.call('change', note);
53081               });
53082             }
53083           }
53084
53085           function clickComment(d3_event, d) {
53086             this.blur(); // avoid keeping focus on the button - #4641
53087
53088             var osm = services.osm;
53089
53090             if (osm) {
53091               osm.postNoteUpdate(d, d.status, function (err, note) {
53092                 dispatch$1.call('change', note);
53093               });
53094             }
53095           }
53096
53097           noteEditor.note = function (val) {
53098             if (!arguments.length) return _note;
53099             _note = val;
53100             return noteEditor;
53101           };
53102
53103           noteEditor.newNote = function (val) {
53104             if (!arguments.length) return _newNote;
53105             _newNote = val;
53106             return noteEditor;
53107           };
53108
53109           return utilRebind(noteEditor, dispatch$1, 'on');
53110         }
53111
53112         function modeSelectNote(context, selectedNoteID) {
53113           var mode = {
53114             id: 'select-note',
53115             button: 'browse'
53116           };
53117
53118           var _keybinding = utilKeybinding('select-note');
53119
53120           var _noteEditor = uiNoteEditor(context).on('change', function () {
53121             context.map().pan([0, 0]); // trigger a redraw
53122
53123             var note = checkSelectedID();
53124             if (!note) return;
53125             context.ui().sidebar.show(_noteEditor.note(note));
53126           });
53127
53128           var _behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
53129           var _newFeature = false;
53130
53131           function checkSelectedID() {
53132             if (!services.osm) return;
53133             var note = services.osm.getNote(selectedNoteID);
53134
53135             if (!note) {
53136               context.enter(modeBrowse(context));
53137             }
53138
53139             return note;
53140           } // class the note as selected, or return to browse mode if the note is gone
53141
53142
53143           function selectNote(d3_event, drawn) {
53144             if (!checkSelectedID()) return;
53145             var selection = context.surface().selectAll('.layer-notes .note-' + selectedNoteID);
53146
53147             if (selection.empty()) {
53148               // Return to browse mode if selected DOM elements have
53149               // disappeared because the user moved them out of view..
53150               var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
53151
53152               if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
53153                 context.enter(modeBrowse(context));
53154               }
53155             } else {
53156               selection.classed('selected', true);
53157               context.selectedNoteID(selectedNoteID);
53158             }
53159           }
53160
53161           function esc() {
53162             if (context.container().select('.combobox').size()) return;
53163             context.enter(modeBrowse(context));
53164           }
53165
53166           mode.zoomToSelected = function () {
53167             if (!services.osm) return;
53168             var note = services.osm.getNote(selectedNoteID);
53169
53170             if (note) {
53171               context.map().centerZoomEase(note.loc, 20);
53172             }
53173           };
53174
53175           mode.newFeature = function (val) {
53176             if (!arguments.length) return _newFeature;
53177             _newFeature = val;
53178             return mode;
53179           };
53180
53181           mode.enter = function () {
53182             var note = checkSelectedID();
53183             if (!note) return;
53184
53185             _behaviors.forEach(context.install);
53186
53187             _keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
53188
53189             select(document).call(_keybinding);
53190             selectNote();
53191             var sidebar = context.ui().sidebar;
53192             sidebar.show(_noteEditor.note(note).newNote(_newFeature)); // expand the sidebar, avoid obscuring the note if needed
53193
53194             sidebar.expand(sidebar.intersects(note.extent()));
53195             context.map().on('drawn.select', selectNote);
53196           };
53197
53198           mode.exit = function () {
53199             _behaviors.forEach(context.uninstall);
53200
53201             select(document).call(_keybinding.unbind);
53202             context.surface().selectAll('.layer-notes .selected').classed('selected hover', false);
53203             context.map().on('drawn.select', null);
53204             context.ui().sidebar.hide();
53205             context.selectedNoteID(null);
53206           };
53207
53208           return mode;
53209         }
53210
53211         function modeDragNote(context) {
53212           var mode = {
53213             id: 'drag-note',
53214             button: 'browse'
53215           };
53216           var edit = behaviorEdit(context);
53217
53218           var _nudgeInterval;
53219
53220           var _lastLoc;
53221
53222           var _note; // most current note.. dragged note may have stale datum.
53223
53224
53225           function startNudge(d3_event, nudge) {
53226             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
53227             _nudgeInterval = window.setInterval(function () {
53228               context.map().pan(nudge);
53229               doMove(d3_event, nudge);
53230             }, 50);
53231           }
53232
53233           function stopNudge() {
53234             if (_nudgeInterval) {
53235               window.clearInterval(_nudgeInterval);
53236               _nudgeInterval = null;
53237             }
53238           }
53239
53240           function origin(note) {
53241             return context.projection(note.loc);
53242           }
53243
53244           function start(d3_event, note) {
53245             _note = note;
53246             var osm = services.osm;
53247
53248             if (osm) {
53249               // Get latest note from cache.. The marker may have a stale datum bound to it
53250               // and dragging it around can sometimes delete the users note comment.
53251               _note = osm.getNote(_note.id);
53252             }
53253
53254             context.surface().selectAll('.note-' + _note.id).classed('active', true);
53255             context.perform(actionNoop());
53256             context.enter(mode);
53257             context.selectedNoteID(_note.id);
53258           }
53259
53260           function move(d3_event, entity, point) {
53261             d3_event.stopPropagation();
53262             _lastLoc = context.projection.invert(point);
53263             doMove(d3_event);
53264             var nudge = geoViewportEdge(point, context.map().dimensions());
53265
53266             if (nudge) {
53267               startNudge(d3_event, nudge);
53268             } else {
53269               stopNudge();
53270             }
53271           }
53272
53273           function doMove(d3_event, nudge) {
53274             nudge = nudge || [0, 0];
53275             var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
53276             var currMouse = geoVecSubtract(currPoint, nudge);
53277             var loc = context.projection.invert(currMouse);
53278             _note = _note.move(loc);
53279             var osm = services.osm;
53280
53281             if (osm) {
53282               osm.replaceNote(_note); // update note cache
53283             }
53284
53285             context.replace(actionNoop()); // trigger redraw
53286           }
53287
53288           function end() {
53289             context.replace(actionNoop()); // trigger redraw
53290
53291             context.selectedNoteID(_note.id).enter(modeSelectNote(context, _note.id));
53292           }
53293
53294           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);
53295
53296           mode.enter = function () {
53297             context.install(edit);
53298           };
53299
53300           mode.exit = function () {
53301             context.ui().sidebar.hover.cancel();
53302             context.uninstall(edit);
53303             context.surface().selectAll('.active').classed('active', false);
53304             stopNudge();
53305           };
53306
53307           mode.behavior = drag;
53308           return mode;
53309         }
53310
53311         function uiDataHeader() {
53312           var _datum;
53313
53314           function dataHeader(selection) {
53315             var header = selection.selectAll('.data-header').data(_datum ? [_datum] : [], function (d) {
53316               return d.__featurehash__;
53317             });
53318             header.exit().remove();
53319             var headerEnter = header.enter().append('div').attr('class', 'data-header');
53320             var iconEnter = headerEnter.append('div').attr('class', 'data-header-icon');
53321             iconEnter.append('div').attr('class', 'preset-icon-28').call(svgIcon('#iD-icon-data', 'note-fill'));
53322             headerEnter.append('div').attr('class', 'data-header-label').html(_t.html('map_data.layers.custom.title'));
53323           }
53324
53325           dataHeader.datum = function (val) {
53326             if (!arguments.length) return _datum;
53327             _datum = val;
53328             return this;
53329           };
53330
53331           return dataHeader;
53332         }
53333
53334         // It is keyed on the `value` of the entry. Data should be an array of objects like:
53335         //   [{
53336         //       value:   'string value',  // required
53337         //       display: 'label html'     // optional
53338         //       title:   'hover text'     // optional
53339         //       terms:   ['search terms'] // optional
53340         //   }, ...]
53341
53342         var _comboHideTimerID;
53343
53344         function uiCombobox(context, klass) {
53345           var dispatch$1 = dispatch('accept', 'cancel');
53346           var container = context.container();
53347           var _suggestions = [];
53348           var _data = [];
53349           var _fetched = {};
53350           var _selected = null;
53351           var _canAutocomplete = true;
53352           var _caseSensitive = false;
53353           var _cancelFetch = false;
53354           var _minItems = 2;
53355           var _tDown = 0;
53356
53357           var _mouseEnterHandler, _mouseLeaveHandler;
53358
53359           var _fetcher = function _fetcher(val, cb) {
53360             cb(_data.filter(function (d) {
53361               var terms = d.terms || [];
53362               terms.push(d.value);
53363               return terms.some(function (term) {
53364                 return term.toString().toLowerCase().indexOf(val.toLowerCase()) !== -1;
53365               });
53366             }));
53367           };
53368
53369           var combobox = function combobox(input, attachTo) {
53370             if (!input || input.empty()) return;
53371             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 () {
53372               var parent = this.parentNode;
53373               var sibling = this.nextSibling;
53374               select(parent).selectAll('.combobox-caret').filter(function (d) {
53375                 return d === input.node();
53376               }).data([input.node()]).enter().insert('div', function () {
53377                 return sibling;
53378               }).attr('class', 'combobox-caret').on('mousedown.combo-caret', function (d3_event) {
53379                 d3_event.preventDefault(); // don't steal focus from input
53380
53381                 input.node().focus(); // focus the input as if it was clicked
53382
53383                 mousedown(d3_event);
53384               }).on('mouseup.combo-caret', function (d3_event) {
53385                 d3_event.preventDefault(); // don't steal focus from input
53386
53387                 mouseup(d3_event);
53388               });
53389             });
53390
53391             function mousedown(d3_event) {
53392               if (d3_event.button !== 0) return; // left click only
53393
53394               _tDown = +new Date(); // clear selection
53395
53396               var start = input.property('selectionStart');
53397               var end = input.property('selectionEnd');
53398
53399               if (start !== end) {
53400                 var val = utilGetSetValue(input);
53401                 input.node().setSelectionRange(val.length, val.length);
53402                 return;
53403               }
53404
53405               input.on('mouseup.combo-input', mouseup);
53406             }
53407
53408             function mouseup(d3_event) {
53409               input.on('mouseup.combo-input', null);
53410               if (d3_event.button !== 0) return; // left click only
53411
53412               if (input.node() !== document.activeElement) return; // exit if this input is not focused
53413
53414               var start = input.property('selectionStart');
53415               var end = input.property('selectionEnd');
53416               if (start !== end) return; // exit if user is selecting
53417               // not showing or showing for a different field - try to show it.
53418
53419               var combo = container.selectAll('.combobox');
53420
53421               if (combo.empty() || combo.datum() !== input.node()) {
53422                 var tOrig = _tDown;
53423                 window.setTimeout(function () {
53424                   if (tOrig !== _tDown) return; // exit if user double clicked
53425
53426                   fetchComboData('', function () {
53427                     show();
53428                     render();
53429                   });
53430                 }, 250);
53431               } else {
53432                 hide();
53433               }
53434             }
53435
53436             function focus() {
53437               fetchComboData(''); // prefetch values (may warm taginfo cache)
53438             }
53439
53440             function blur() {
53441               _comboHideTimerID = window.setTimeout(hide, 75);
53442             }
53443
53444             function show() {
53445               hide(); // remove any existing
53446
53447               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) {
53448                 // prevent moving focus out of the input field
53449                 d3_event.preventDefault();
53450               });
53451               container.on('scroll.combo-scroll', render, true);
53452             }
53453
53454             function hide() {
53455               if (_comboHideTimerID) {
53456                 window.clearTimeout(_comboHideTimerID);
53457                 _comboHideTimerID = undefined;
53458               }
53459
53460               container.selectAll('.combobox').remove();
53461               container.on('scroll.combo-scroll', null);
53462             }
53463
53464             function keydown(d3_event) {
53465               var shown = !container.selectAll('.combobox').empty();
53466               var tagName = input.node() ? input.node().tagName.toLowerCase() : '';
53467
53468               switch (d3_event.keyCode) {
53469                 case 8: // ⌫ Backspace
53470
53471                 case 46:
53472                   // ⌦ Delete
53473                   d3_event.stopPropagation();
53474                   _selected = null;
53475                   render();
53476                   input.on('input.combo-input', function () {
53477                     var start = input.property('selectionStart');
53478                     input.node().setSelectionRange(start, start);
53479                     input.on('input.combo-input', change);
53480                   });
53481                   break;
53482
53483                 case 9:
53484                   // ⇥ Tab
53485                   accept();
53486                   break;
53487
53488                 case 13:
53489                   // ↩ Return
53490                   d3_event.preventDefault();
53491                   d3_event.stopPropagation();
53492                   break;
53493
53494                 case 38:
53495                   // ↑ Up arrow
53496                   if (tagName === 'textarea' && !shown) return;
53497                   d3_event.preventDefault();
53498
53499                   if (tagName === 'input' && !shown) {
53500                     show();
53501                   }
53502
53503                   nav(-1);
53504                   break;
53505
53506                 case 40:
53507                   // ↓ Down arrow
53508                   if (tagName === 'textarea' && !shown) return;
53509                   d3_event.preventDefault();
53510
53511                   if (tagName === 'input' && !shown) {
53512                     show();
53513                   }
53514
53515                   nav(+1);
53516                   break;
53517               }
53518             }
53519
53520             function keyup(d3_event) {
53521               switch (d3_event.keyCode) {
53522                 case 27:
53523                   // ⎋ Escape
53524                   cancel();
53525                   break;
53526
53527                 case 13:
53528                   // ↩ Return
53529                   accept();
53530                   break;
53531               }
53532             } // Called whenever the input value is changed (e.g. on typing)
53533
53534
53535             function change() {
53536               fetchComboData(value(), function () {
53537                 _selected = null;
53538                 var val = input.property('value');
53539
53540                 if (_suggestions.length) {
53541                   if (input.property('selectionEnd') === val.length) {
53542                     _selected = tryAutocomplete();
53543                   }
53544
53545                   if (!_selected) {
53546                     _selected = val;
53547                   }
53548                 }
53549
53550                 if (val.length) {
53551                   var combo = container.selectAll('.combobox');
53552
53553                   if (combo.empty()) {
53554                     show();
53555                   }
53556                 } else {
53557                   hide();
53558                 }
53559
53560                 render();
53561               });
53562             } // Called when the user presses up/down arrows to navigate the list
53563
53564
53565             function nav(dir) {
53566               if (_suggestions.length) {
53567                 // try to determine previously selected index..
53568                 var index = -1;
53569
53570                 for (var i = 0; i < _suggestions.length; i++) {
53571                   if (_selected && _suggestions[i].value === _selected) {
53572                     index = i;
53573                     break;
53574                   }
53575                 } // pick new _selected
53576
53577
53578                 index = Math.max(Math.min(index + dir, _suggestions.length - 1), 0);
53579                 _selected = _suggestions[index].value;
53580                 input.property('value', _selected);
53581               }
53582
53583               render();
53584               ensureVisible();
53585             }
53586
53587             function ensureVisible() {
53588               var combo = container.selectAll('.combobox');
53589               if (combo.empty()) return;
53590               var containerRect = container.node().getBoundingClientRect();
53591               var comboRect = combo.node().getBoundingClientRect();
53592
53593               if (comboRect.bottom > containerRect.bottom) {
53594                 var node = attachTo ? attachTo.node() : input.node();
53595                 node.scrollIntoView({
53596                   behavior: 'instant',
53597                   block: 'center'
53598                 });
53599                 render();
53600               } // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move
53601
53602
53603               var selected = combo.selectAll('.combobox-option.selected').node();
53604
53605               if (selected) {
53606                 selected.scrollIntoView({
53607                   behavior: 'smooth',
53608                   block: 'nearest'
53609                 });
53610               }
53611             }
53612
53613             function value() {
53614               var value = input.property('value');
53615               var start = input.property('selectionStart');
53616               var end = input.property('selectionEnd');
53617
53618               if (start && end) {
53619                 value = value.substring(0, start);
53620               }
53621
53622               return value;
53623             }
53624
53625             function fetchComboData(v, cb) {
53626               _cancelFetch = false;
53627
53628               _fetcher.call(input, v, function (results) {
53629                 // already chose a value, don't overwrite or autocomplete it
53630                 if (_cancelFetch) return;
53631                 _suggestions = results;
53632                 results.forEach(function (d) {
53633                   _fetched[d.value] = d;
53634                 });
53635
53636                 if (cb) {
53637                   cb();
53638                 }
53639               });
53640             }
53641
53642             function tryAutocomplete() {
53643               if (!_canAutocomplete) return;
53644               var val = _caseSensitive ? value() : value().toLowerCase();
53645               if (!val) return; // Don't autocomplete if user is typing a number - #4935
53646
53647               if (!isNaN(parseFloat(val)) && isFinite(val)) return;
53648               var bestIndex = -1;
53649
53650               for (var i = 0; i < _suggestions.length; i++) {
53651                 var suggestion = _suggestions[i].value;
53652                 var compare = _caseSensitive ? suggestion : suggestion.toLowerCase(); // if search string matches suggestion exactly, pick it..
53653
53654                 if (compare === val) {
53655                   bestIndex = i;
53656                   break; // otherwise lock in the first result that starts with the search string..
53657                 } else if (bestIndex === -1 && compare.indexOf(val) === 0) {
53658                   bestIndex = i;
53659                 }
53660               }
53661
53662               if (bestIndex !== -1) {
53663                 var bestVal = _suggestions[bestIndex].value;
53664                 input.property('value', bestVal);
53665                 input.node().setSelectionRange(val.length, bestVal.length);
53666                 return bestVal;
53667               }
53668             }
53669
53670             function render() {
53671               if (_suggestions.length < _minItems || document.activeElement !== input.node()) {
53672                 hide();
53673                 return;
53674               }
53675
53676               var shown = !container.selectAll('.combobox').empty();
53677               if (!shown) return;
53678               var combo = container.selectAll('.combobox');
53679               var options = combo.selectAll('.combobox-option').data(_suggestions, function (d) {
53680                 return d.value;
53681               });
53682               options.exit().remove(); // enter/update
53683
53684               options.enter().append('a').attr('class', 'combobox-option').attr('title', function (d) {
53685                 return d.title;
53686               }).html(function (d) {
53687                 return d.display || d.value;
53688               }).on('mouseenter', _mouseEnterHandler).on('mouseleave', _mouseLeaveHandler).merge(options).classed('selected', function (d) {
53689                 return d.value === _selected;
53690               }).on('click.combo-option', accept).order();
53691               var node = attachTo ? attachTo.node() : input.node();
53692               var containerRect = container.node().getBoundingClientRect();
53693               var rect = node.getBoundingClientRect();
53694               combo.style('left', rect.left + 5 - containerRect.left + 'px').style('width', rect.width - 10 + 'px').style('top', rect.height + rect.top - containerRect.top + 'px');
53695             } // Dispatches an 'accept' event
53696             // Then hides the combobox.
53697
53698
53699             function accept(d3_event, d) {
53700               _cancelFetch = true;
53701               var thiz = input.node();
53702
53703               if (d) {
53704                 // user clicked on a suggestion
53705                 utilGetSetValue(input, d.value); // replace field contents
53706
53707                 utilTriggerEvent(input, 'change');
53708               } // clear (and keep) selection
53709
53710
53711               var val = utilGetSetValue(input);
53712               thiz.setSelectionRange(val.length, val.length);
53713               d = _fetched[val];
53714               dispatch$1.call('accept', thiz, d, val);
53715               hide();
53716             } // Dispatches an 'cancel' event
53717             // Then hides the combobox.
53718
53719
53720             function cancel() {
53721               _cancelFetch = true;
53722               var thiz = input.node(); // clear (and remove) selection, and replace field contents
53723
53724               var val = utilGetSetValue(input);
53725               var start = input.property('selectionStart');
53726               var end = input.property('selectionEnd');
53727               val = val.slice(0, start) + val.slice(end);
53728               utilGetSetValue(input, val);
53729               thiz.setSelectionRange(val.length, val.length);
53730               dispatch$1.call('cancel', thiz);
53731               hide();
53732             }
53733           };
53734
53735           combobox.canAutocomplete = function (val) {
53736             if (!arguments.length) return _canAutocomplete;
53737             _canAutocomplete = val;
53738             return combobox;
53739           };
53740
53741           combobox.caseSensitive = function (val) {
53742             if (!arguments.length) return _caseSensitive;
53743             _caseSensitive = val;
53744             return combobox;
53745           };
53746
53747           combobox.data = function (val) {
53748             if (!arguments.length) return _data;
53749             _data = val;
53750             return combobox;
53751           };
53752
53753           combobox.fetcher = function (val) {
53754             if (!arguments.length) return _fetcher;
53755             _fetcher = val;
53756             return combobox;
53757           };
53758
53759           combobox.minItems = function (val) {
53760             if (!arguments.length) return _minItems;
53761             _minItems = val;
53762             return combobox;
53763           };
53764
53765           combobox.itemsMouseEnter = function (val) {
53766             if (!arguments.length) return _mouseEnterHandler;
53767             _mouseEnterHandler = val;
53768             return combobox;
53769           };
53770
53771           combobox.itemsMouseLeave = function (val) {
53772             if (!arguments.length) return _mouseLeaveHandler;
53773             _mouseLeaveHandler = val;
53774             return combobox;
53775           };
53776
53777           return utilRebind(combobox, dispatch$1, 'on');
53778         }
53779
53780         uiCombobox.off = function (input, context) {
53781           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);
53782           context.container().on('scroll.combo-scroll', null);
53783         };
53784
53785         // hide class, which sets display=none, and a d3 transition for opacity.
53786         // this will cause blinking when called repeatedly, so check that the
53787         // value actually changes between calls.
53788
53789         function uiToggle(show, callback) {
53790           return function (selection) {
53791             selection.style('opacity', show ? 0 : 1).classed('hide', false).transition().style('opacity', show ? 1 : 0).on('end', function () {
53792               select(this).classed('hide', !show).style('opacity', null);
53793               if (callback) callback.apply(this);
53794             });
53795           };
53796         }
53797
53798         function uiDisclosure(context, key, expandedDefault) {
53799           var dispatch$1 = dispatch('toggled');
53800
53801           var _expanded;
53802
53803           var _label = utilFunctor('');
53804
53805           var _updatePreference = true;
53806
53807           var _content = function _content() {};
53808
53809           var disclosure = function disclosure(selection) {
53810             if (_expanded === undefined || _expanded === null) {
53811               // loading _expanded here allows it to be reset by calling `disclosure.expanded(null)`
53812               var preference = corePreferences('disclosure.' + key + '.expanded');
53813               _expanded = preference === null ? !!expandedDefault : preference === 'true';
53814             }
53815
53816             var hideToggle = selection.selectAll('.hide-toggle-' + key).data([0]); // enter
53817
53818             var hideToggleEnter = hideToggle.enter().append('a').attr('href', '#').attr('class', 'hide-toggle hide-toggle-' + key).call(svgIcon('', 'pre-text', 'hide-toggle-icon'));
53819             hideToggleEnter.append('span').attr('class', 'hide-toggle-text'); // update
53820
53821             hideToggle = hideToggleEnter.merge(hideToggle);
53822             hideToggle.on('click', toggle).classed('expanded', _expanded);
53823             hideToggle.selectAll('.hide-toggle-text').html(_label());
53824             hideToggle.selectAll('.hide-toggle-icon').attr('xlink:href', _expanded ? '#iD-icon-down' : _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward');
53825             var wrap = selection.selectAll('.disclosure-wrap').data([0]); // enter/update
53826
53827             wrap = wrap.enter().append('div').attr('class', 'disclosure-wrap disclosure-wrap-' + key).merge(wrap).classed('hide', !_expanded);
53828
53829             if (_expanded) {
53830               wrap.call(_content);
53831             }
53832
53833             function toggle(d3_event) {
53834               d3_event.preventDefault();
53835               _expanded = !_expanded;
53836
53837               if (_updatePreference) {
53838                 corePreferences('disclosure.' + key + '.expanded', _expanded);
53839               }
53840
53841               hideToggle.classed('expanded', _expanded);
53842               hideToggle.selectAll('.hide-toggle-icon').attr('xlink:href', _expanded ? '#iD-icon-down' : _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward');
53843               wrap.call(uiToggle(_expanded));
53844
53845               if (_expanded) {
53846                 wrap.call(_content);
53847               }
53848
53849               dispatch$1.call('toggled', this, _expanded);
53850             }
53851           };
53852
53853           disclosure.label = function (val) {
53854             if (!arguments.length) return _label;
53855             _label = utilFunctor(val);
53856             return disclosure;
53857           };
53858
53859           disclosure.expanded = function (val) {
53860             if (!arguments.length) return _expanded;
53861             _expanded = val;
53862             return disclosure;
53863           };
53864
53865           disclosure.updatePreference = function (val) {
53866             if (!arguments.length) return _updatePreference;
53867             _updatePreference = val;
53868             return disclosure;
53869           };
53870
53871           disclosure.content = function (val) {
53872             if (!arguments.length) return _content;
53873             _content = val;
53874             return disclosure;
53875           };
53876
53877           return utilRebind(disclosure, dispatch$1, 'on');
53878         }
53879
53880         // Can be labeled and collapsible.
53881
53882         function uiSection(id, context) {
53883           var _classes = utilFunctor('');
53884
53885           var _shouldDisplay;
53886
53887           var _content;
53888
53889           var _disclosure;
53890
53891           var _label;
53892
53893           var _expandedByDefault = utilFunctor(true);
53894
53895           var _disclosureContent;
53896
53897           var _disclosureExpanded;
53898
53899           var _containerSelection = select(null);
53900
53901           var section = {
53902             id: id
53903           };
53904
53905           section.classes = function (val) {
53906             if (!arguments.length) return _classes;
53907             _classes = utilFunctor(val);
53908             return section;
53909           };
53910
53911           section.label = function (val) {
53912             if (!arguments.length) return _label;
53913             _label = utilFunctor(val);
53914             return section;
53915           };
53916
53917           section.expandedByDefault = function (val) {
53918             if (!arguments.length) return _expandedByDefault;
53919             _expandedByDefault = utilFunctor(val);
53920             return section;
53921           };
53922
53923           section.shouldDisplay = function (val) {
53924             if (!arguments.length) return _shouldDisplay;
53925             _shouldDisplay = utilFunctor(val);
53926             return section;
53927           };
53928
53929           section.content = function (val) {
53930             if (!arguments.length) return _content;
53931             _content = val;
53932             return section;
53933           };
53934
53935           section.disclosureContent = function (val) {
53936             if (!arguments.length) return _disclosureContent;
53937             _disclosureContent = val;
53938             return section;
53939           };
53940
53941           section.disclosureExpanded = function (val) {
53942             if (!arguments.length) return _disclosureExpanded;
53943             _disclosureExpanded = val;
53944             return section;
53945           }; // may be called multiple times
53946
53947
53948           section.render = function (selection) {
53949             _containerSelection = selection.selectAll('.section-' + id).data([0]);
53950
53951             var sectionEnter = _containerSelection.enter().append('div').attr('class', 'section section-' + id + ' ' + (_classes && _classes() || ''));
53952
53953             _containerSelection = sectionEnter.merge(_containerSelection);
53954
53955             _containerSelection.call(renderContent);
53956           };
53957
53958           section.reRender = function () {
53959             _containerSelection.call(renderContent);
53960           };
53961
53962           section.selection = function () {
53963             return _containerSelection;
53964           };
53965
53966           section.disclosure = function () {
53967             return _disclosure;
53968           }; // may be called multiple times
53969
53970
53971           function renderContent(selection) {
53972             if (_shouldDisplay) {
53973               var shouldDisplay = _shouldDisplay();
53974
53975               selection.classed('hide', !shouldDisplay);
53976
53977               if (!shouldDisplay) {
53978                 selection.html('');
53979                 return;
53980               }
53981             }
53982
53983             if (_disclosureContent) {
53984               if (!_disclosure) {
53985                 _disclosure = uiDisclosure(context, id.replace(/-/g, '_'), _expandedByDefault()).label(_label || '')
53986                 /*.on('toggled', function(expanded) {
53987                     if (expanded) { selection.node().parentNode.scrollTop += 200; }
53988                 })*/
53989                 .content(_disclosureContent);
53990               }
53991
53992               if (_disclosureExpanded !== undefined) {
53993                 _disclosure.expanded(_disclosureExpanded);
53994
53995                 _disclosureExpanded = undefined;
53996               }
53997
53998               selection.call(_disclosure);
53999               return;
54000             }
54001
54002             if (_content) {
54003               selection.call(_content);
54004             }
54005           }
54006
54007           return section;
54008         }
54009
54010         // {
54011         //   key: 'string',     // required
54012         //   value: 'string'    // optional
54013         // }
54014         //   -or-
54015         // {
54016         //   qid: 'string'      // brand wikidata  (e.g. 'Q37158')
54017         // }
54018         //
54019
54020         function uiTagReference(what) {
54021           var wikibase = what.qid ? services.wikidata : services.osmWikibase;
54022           var tagReference = {};
54023
54024           var _button = select(null);
54025
54026           var _body = select(null);
54027
54028           var _loaded;
54029
54030           var _showing;
54031
54032           function load() {
54033             if (!wikibase) return;
54034
54035             _button.classed('tag-reference-loading', true);
54036
54037             wikibase.getDocs(what, gotDocs);
54038           }
54039
54040           function gotDocs(err, docs) {
54041             _body.html('');
54042
54043             if (!docs || !docs.title) {
54044               _body.append('p').attr('class', 'tag-reference-description').html(_t.html('inspector.no_documentation_key'));
54045
54046               done();
54047               return;
54048             }
54049
54050             if (docs.imageURL) {
54051               _body.append('img').attr('class', 'tag-reference-wiki-image').attr('src', docs.imageURL).on('load', function () {
54052                 done();
54053               }).on('error', function () {
54054                 select(this).remove();
54055                 done();
54056               });
54057             } else {
54058               done();
54059             }
54060
54061             _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'));
54062
54063             if (docs.wiki) {
54064               _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));
54065             } // Add link to info about "good changeset comments" - #2923
54066
54067
54068             if (what.key === 'comment') {
54069               _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'));
54070             }
54071           }
54072
54073           function done() {
54074             _loaded = true;
54075
54076             _button.classed('tag-reference-loading', false);
54077
54078             _body.classed('expanded', true).transition().duration(200).style('max-height', '200px').style('opacity', '1');
54079
54080             _showing = true;
54081
54082             _button.selectAll('svg.icon use').each(function () {
54083               var iconUse = select(this);
54084
54085               if (iconUse.attr('href') === '#iD-icon-info') {
54086                 iconUse.attr('href', '#iD-icon-info-filled');
54087               }
54088             });
54089           }
54090
54091           function hide() {
54092             _body.transition().duration(200).style('max-height', '0px').style('opacity', '0').on('end', function () {
54093               _body.classed('expanded', false);
54094             });
54095
54096             _showing = false;
54097
54098             _button.selectAll('svg.icon use').each(function () {
54099               var iconUse = select(this);
54100
54101               if (iconUse.attr('href') === '#iD-icon-info-filled') {
54102                 iconUse.attr('href', '#iD-icon-info');
54103               }
54104             });
54105           }
54106
54107           tagReference.button = function (selection, klass, iconName) {
54108             _button = selection.selectAll('.tag-reference-button').data([0]);
54109             _button = _button.enter().append('button').attr('class', 'tag-reference-button ' + (klass || '')).attr('title', _t('icons.information')).call(svgIcon('#iD-icon-' + (iconName || 'inspect'))).merge(_button);
54110
54111             _button.on('click', function (d3_event) {
54112               d3_event.stopPropagation();
54113               d3_event.preventDefault();
54114               this.blur(); // avoid keeping focus on the button - #4641
54115
54116               if (_showing) {
54117                 hide();
54118               } else if (_loaded) {
54119                 done();
54120               } else {
54121                 load();
54122               }
54123             });
54124           };
54125
54126           tagReference.body = function (selection) {
54127             var itemID = what.qid || what.key + '-' + (what.value || '');
54128             _body = selection.selectAll('.tag-reference-body').data([itemID], function (d) {
54129               return d;
54130             });
54131
54132             _body.exit().remove();
54133
54134             _body = _body.enter().append('div').attr('class', 'tag-reference-body').style('max-height', '0').style('opacity', '0').merge(_body);
54135
54136             if (_showing === false) {
54137               hide();
54138             }
54139           };
54140
54141           tagReference.showing = function (val) {
54142             if (!arguments.length) return _showing;
54143             _showing = val;
54144             return tagReference;
54145           };
54146
54147           return tagReference;
54148         }
54149
54150         function uiSectionRawTagEditor(id, context) {
54151           var section = uiSection(id, context).classes('raw-tag-editor').label(function () {
54152             var count = Object.keys(_tags).filter(function (d) {
54153               return d;
54154             }).length;
54155             return _t('inspector.title_count', {
54156               title: _t.html('inspector.tags'),
54157               count: count
54158             });
54159           }).expandedByDefault(false).disclosureContent(renderDisclosureContent);
54160           var taginfo = services.taginfo;
54161           var dispatch$1 = dispatch('change');
54162           var availableViews = [{
54163             id: 'list',
54164             icon: '#fas-th-list'
54165           }, {
54166             id: 'text',
54167             icon: '#fas-i-cursor'
54168           }];
54169
54170           var _tagView = corePreferences('raw-tag-editor-view') || 'list'; // 'list, 'text'
54171
54172
54173           var _readOnlyTags = []; // the keys in the order we want them to display
54174
54175           var _orderedKeys = [];
54176           var _showBlank = false;
54177           var _pendingChange = null;
54178
54179           var _state;
54180
54181           var _presets;
54182
54183           var _tags;
54184
54185           var _entityIDs;
54186
54187           var _didInteract = false;
54188
54189           function interacted() {
54190             _didInteract = true;
54191           }
54192
54193           function renderDisclosureContent(wrap) {
54194             // remove deleted keys
54195             _orderedKeys = _orderedKeys.filter(function (key) {
54196               return _tags[key] !== undefined;
54197             }); // When switching to a different entity or changing the state (hover/select)
54198             // reorder the keys alphabetically.
54199             // We trigger this by emptying the `_orderedKeys` array, then it will be rebuilt here.
54200             // Otherwise leave their order alone - #5857, #5927
54201
54202             var all = Object.keys(_tags).sort();
54203             var missingKeys = utilArrayDifference(all, _orderedKeys);
54204
54205             for (var i in missingKeys) {
54206               _orderedKeys.push(missingKeys[i]);
54207             } // assemble row data
54208
54209
54210             var rowData = _orderedKeys.map(function (key, i) {
54211               return {
54212                 index: i,
54213                 key: key,
54214                 value: _tags[key]
54215               };
54216             }); // append blank row last, if necessary
54217
54218
54219             if (!rowData.length || _showBlank) {
54220               _showBlank = false;
54221               rowData.push({
54222                 index: rowData.length,
54223                 key: '',
54224                 value: ''
54225               });
54226             } // View Options
54227
54228
54229             var options = wrap.selectAll('.raw-tag-options').data([0]);
54230             options.exit().remove();
54231             var optionsEnter = options.enter().insert('div', ':first-child').attr('class', 'raw-tag-options');
54232             var optionEnter = optionsEnter.selectAll('.raw-tag-option').data(availableViews, function (d) {
54233               return d.id;
54234             }).enter();
54235             optionEnter.append('button').attr('class', function (d) {
54236               return 'raw-tag-option raw-tag-option-' + d.id + (_tagView === d.id ? ' selected' : '');
54237             }).attr('title', function (d) {
54238               return _t('icons.' + d.id);
54239             }).on('click', function (d3_event, d) {
54240               _tagView = d.id;
54241               corePreferences('raw-tag-editor-view', d.id);
54242               wrap.selectAll('.raw-tag-option').classed('selected', function (datum) {
54243                 return datum === d;
54244               });
54245               wrap.selectAll('.tag-text').classed('hide', d.id !== 'text').each(setTextareaHeight);
54246               wrap.selectAll('.tag-list, .add-row').classed('hide', d.id !== 'list');
54247             }).each(function (d) {
54248               select(this).call(svgIcon(d.icon));
54249             }); // View as Text
54250
54251             var textData = rowsToText(rowData);
54252             var textarea = wrap.selectAll('.tag-text').data([0]);
54253             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);
54254             textarea.call(utilGetSetValue, textData).each(setTextareaHeight).on('input', setTextareaHeight).on('focus', interacted).on('blur', textChanged).on('change', textChanged); // View as List
54255
54256             var list = wrap.selectAll('.tag-list').data([0]);
54257             list = list.enter().append('ul').attr('class', 'tag-list' + (_tagView !== 'list' ? ' hide' : '')).merge(list); // Container for the Add button
54258
54259             var addRowEnter = wrap.selectAll('.add-row').data([0]).enter().append('div').attr('class', 'add-row' + (_tagView !== 'list' ? ' hide' : ''));
54260             addRowEnter.append('button').attr('class', 'add-tag').call(svgIcon('#iD-icon-plus', 'light')).on('click', addTag);
54261             addRowEnter.append('div').attr('class', 'space-value'); // preserve space
54262
54263             addRowEnter.append('div').attr('class', 'space-buttons'); // preserve space
54264             // Tag list items
54265
54266             var items = list.selectAll('.tag-row').data(rowData, function (d) {
54267               return d.key;
54268             });
54269             items.exit().each(unbind).remove(); // Enter
54270
54271             var itemsEnter = items.enter().append('li').attr('class', 'tag-row').classed('readonly', isReadOnly);
54272             var innerWrap = itemsEnter.append('div').attr('class', 'inner-wrap');
54273             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);
54274             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);
54275             innerWrap.append('button').attr('class', 'form-field-button remove').attr('title', _t('icons.remove')).call(svgIcon('#iD-operation-delete')); // Update
54276
54277             items = items.merge(itemsEnter).sort(function (a, b) {
54278               return a.index - b.index;
54279             });
54280             items.each(function (d) {
54281               var row = select(this);
54282               var key = row.select('input.key'); // propagate bound data
54283
54284               var value = row.select('input.value'); // propagate bound data
54285
54286               if (_entityIDs && taginfo && _state !== 'hover') {
54287                 bindTypeahead(key, value);
54288               }
54289
54290               var referenceOptions = {
54291                 key: d.key
54292               };
54293
54294               if (typeof d.value === 'string') {
54295                 referenceOptions.value = d.value;
54296               }
54297
54298               var reference = uiTagReference(referenceOptions);
54299
54300               if (_state === 'hover') {
54301                 reference.showing(false);
54302               }
54303
54304               row.select('.inner-wrap') // propagate bound data
54305               .call(reference.button);
54306               row.call(reference.body);
54307               row.select('button.remove'); // propagate bound data
54308             });
54309             items.selectAll('input.key').attr('title', function (d) {
54310               return d.key;
54311             }).call(utilGetSetValue, function (d) {
54312               return d.key;
54313             }).attr('readonly', function (d) {
54314               return isReadOnly(d) || typeof d.value !== 'string' || null;
54315             });
54316             items.selectAll('input.value').attr('title', function (d) {
54317               return Array.isArray(d.value) ? d.value.filter(Boolean).join('\n') : d.value;
54318             }).classed('mixed', function (d) {
54319               return Array.isArray(d.value);
54320             }).attr('placeholder', function (d) {
54321               return typeof d.value === 'string' ? null : _t('inspector.multiple_values');
54322             }).call(utilGetSetValue, function (d) {
54323               return typeof d.value === 'string' ? d.value : '';
54324             }).attr('readonly', function (d) {
54325               return isReadOnly(d) || null;
54326             });
54327             items.selectAll('button.remove').on(('PointerEvent' in window ? 'pointer' : 'mouse') + 'down', removeTag); // 'click' fires too late - #5878
54328           }
54329
54330           function isReadOnly(d) {
54331             for (var i = 0; i < _readOnlyTags.length; i++) {
54332               if (d.key.match(_readOnlyTags[i]) !== null) {
54333                 return true;
54334               }
54335             }
54336
54337             return false;
54338           }
54339
54340           function setTextareaHeight() {
54341             if (_tagView !== 'text') return;
54342             var selection = select(this);
54343             var matches = selection.node().value.match(/\n/g);
54344             var lineCount = 2 + Number(matches && matches.length);
54345             var lineHeight = 20;
54346             selection.style('height', lineCount * lineHeight + 'px');
54347           }
54348
54349           function stringify(s) {
54350             return JSON.stringify(s).slice(1, -1); // without leading/trailing "
54351           }
54352
54353           function unstringify(s) {
54354             var leading = '';
54355             var trailing = '';
54356
54357             if (s.length < 1 || s.charAt(0) !== '"') {
54358               leading = '"';
54359             }
54360
54361             if (s.length < 2 || s.charAt(s.length - 1) !== '"' || s.charAt(s.length - 1) === '"' && s.charAt(s.length - 2) === '\\') {
54362               trailing = '"';
54363             }
54364
54365             return JSON.parse(leading + s + trailing);
54366           }
54367
54368           function rowsToText(rows) {
54369             var str = rows.filter(function (row) {
54370               return row.key && row.key.trim() !== '';
54371             }).map(function (row) {
54372               var rawVal = row.value;
54373               if (typeof rawVal !== 'string') rawVal = '*';
54374               var val = rawVal ? stringify(rawVal) : '';
54375               return stringify(row.key) + '=' + val;
54376             }).join('\n');
54377
54378             if (_state !== 'hover' && str.length) {
54379               return str + '\n';
54380             }
54381
54382             return str;
54383           }
54384
54385           function textChanged() {
54386             var newText = this.value.trim();
54387             var newTags = {};
54388             newText.split('\n').forEach(function (row) {
54389               var m = row.match(/^\s*([^=]+)=(.*)$/);
54390
54391               if (m !== null) {
54392                 var k = context.cleanTagKey(unstringify(m[1].trim()));
54393                 var v = context.cleanTagValue(unstringify(m[2].trim()));
54394                 newTags[k] = v;
54395               }
54396             });
54397             var tagDiff = utilTagDiff(_tags, newTags);
54398             if (!tagDiff.length) return;
54399             _pendingChange = _pendingChange || {};
54400             tagDiff.forEach(function (change) {
54401               if (isReadOnly({
54402                 key: change.key
54403               })) return; // skip unchanged multiselection placeholders
54404
54405               if (change.newVal === '*' && typeof change.oldVal !== 'string') return;
54406
54407               if (change.type === '-') {
54408                 _pendingChange[change.key] = undefined;
54409               } else if (change.type === '+') {
54410                 _pendingChange[change.key] = change.newVal || '';
54411               }
54412             });
54413
54414             if (Object.keys(_pendingChange).length === 0) {
54415               _pendingChange = null;
54416               return;
54417             }
54418
54419             scheduleChange();
54420           }
54421
54422           function pushMore(d3_event) {
54423             // if pressing Tab on the last value field with content, add a blank row
54424             if (d3_event.keyCode === 9 && !d3_event.shiftKey && section.selection().selectAll('.tag-list li:last-child input.value').node() === this && utilGetSetValue(select(this))) {
54425               addTag();
54426             }
54427           }
54428
54429           function bindTypeahead(key, value) {
54430             if (isReadOnly(key.datum())) return;
54431
54432             if (Array.isArray(value.datum().value)) {
54433               value.call(uiCombobox(context, 'tag-value').minItems(1).fetcher(function (value, callback) {
54434                 var keyString = utilGetSetValue(key);
54435                 if (!_tags[keyString]) return;
54436
54437                 var data = _tags[keyString].filter(Boolean).map(function (tagValue) {
54438                   return {
54439                     value: tagValue,
54440                     title: tagValue
54441                   };
54442                 });
54443
54444                 callback(data);
54445               }));
54446               return;
54447             }
54448
54449             var geometry = context.graph().geometry(_entityIDs[0]);
54450             key.call(uiCombobox(context, 'tag-key').fetcher(function (value, callback) {
54451               taginfo.keys({
54452                 debounce: true,
54453                 geometry: geometry,
54454                 query: value
54455               }, function (err, data) {
54456                 if (!err) {
54457                   var filtered = data.filter(function (d) {
54458                     return _tags[d.value] === undefined;
54459                   });
54460                   callback(sort(value, filtered));
54461                 }
54462               });
54463             }));
54464             value.call(uiCombobox(context, 'tag-value').fetcher(function (value, callback) {
54465               taginfo.values({
54466                 debounce: true,
54467                 key: utilGetSetValue(key),
54468                 geometry: geometry,
54469                 query: value
54470               }, function (err, data) {
54471                 if (!err) callback(sort(value, data));
54472               });
54473             }));
54474
54475             function sort(value, data) {
54476               var sameletter = [];
54477               var other = [];
54478
54479               for (var i = 0; i < data.length; i++) {
54480                 if (data[i].value.substring(0, value.length) === value) {
54481                   sameletter.push(data[i]);
54482                 } else {
54483                   other.push(data[i]);
54484                 }
54485               }
54486
54487               return sameletter.concat(other);
54488             }
54489           }
54490
54491           function unbind() {
54492             var row = select(this);
54493             row.selectAll('input.key').call(uiCombobox.off, context);
54494             row.selectAll('input.value').call(uiCombobox.off, context);
54495           }
54496
54497           function keyChange(d3_event, d) {
54498             if (select(this).attr('readonly')) return;
54499             var kOld = d.key; // exit if we are currently about to delete this row anyway - #6366
54500
54501             if (_pendingChange && _pendingChange.hasOwnProperty(kOld) && _pendingChange[kOld] === undefined) return;
54502             var kNew = context.cleanTagKey(this.value.trim()); // allow no change if the key should be readonly
54503
54504             if (isReadOnly({
54505               key: kNew
54506             })) {
54507               this.value = kOld;
54508               return;
54509             }
54510
54511             if (kNew && kNew !== kOld && _tags[kNew] !== undefined) {
54512               // new key is already in use, switch focus to the existing row
54513               this.value = kOld; // reset the key
54514
54515               section.selection().selectAll('.tag-list input.value').each(function (d) {
54516                 if (d.key === kNew) {
54517                   // send focus to that other value combo instead
54518                   var input = select(this).node();
54519                   input.focus();
54520                   input.select();
54521                 }
54522               });
54523               return;
54524             }
54525
54526             var row = this.parentNode.parentNode;
54527             var inputVal = select(row).selectAll('input.value');
54528             var vNew = context.cleanTagValue(utilGetSetValue(inputVal));
54529             _pendingChange = _pendingChange || {};
54530
54531             if (kOld) {
54532               _pendingChange[kOld] = undefined;
54533             }
54534
54535             _pendingChange[kNew] = vNew; // update the ordered key index so this row doesn't change position
54536
54537             var existingKeyIndex = _orderedKeys.indexOf(kOld);
54538
54539             if (existingKeyIndex !== -1) _orderedKeys[existingKeyIndex] = kNew;
54540             d.key = kNew; // update datum to avoid exit/enter on tag update
54541
54542             d.value = vNew;
54543             this.value = kNew;
54544             utilGetSetValue(inputVal, vNew);
54545             scheduleChange();
54546           }
54547
54548           function valueChange(d3_event, d) {
54549             if (isReadOnly(d)) return; // exit if this is a multiselection and no value was entered
54550
54551             if (typeof d.value !== 'string' && !this.value) return; // exit if we are currently about to delete this row anyway - #6366
54552
54553             if (_pendingChange && _pendingChange.hasOwnProperty(d.key) && _pendingChange[d.key] === undefined) return;
54554             _pendingChange = _pendingChange || {};
54555             _pendingChange[d.key] = context.cleanTagValue(this.value);
54556             scheduleChange();
54557           }
54558
54559           function removeTag(d3_event, d) {
54560             if (isReadOnly(d)) return;
54561
54562             if (d.key === '') {
54563               // removing the blank row
54564               _showBlank = false;
54565               section.reRender();
54566             } else {
54567               // remove the key from the ordered key index
54568               _orderedKeys = _orderedKeys.filter(function (key) {
54569                 return key !== d.key;
54570               });
54571               _pendingChange = _pendingChange || {};
54572               _pendingChange[d.key] = undefined;
54573               scheduleChange();
54574             }
54575           }
54576
54577           function addTag() {
54578             // Delay render in case this click is blurring an edited combo.
54579             // Without the setTimeout, the `content` render would wipe out the pending tag change.
54580             window.setTimeout(function () {
54581               _showBlank = true;
54582               section.reRender();
54583               section.selection().selectAll('.tag-list li:last-child input.key').node().focus();
54584             }, 20);
54585           }
54586
54587           function scheduleChange() {
54588             // Cache IDs in case the editor is reloaded before the change event is called. - #6028
54589             var entityIDs = _entityIDs; // Delay change in case this change is blurring an edited combo. - #5878
54590
54591             window.setTimeout(function () {
54592               if (!_pendingChange) return;
54593               dispatch$1.call('change', this, entityIDs, _pendingChange);
54594               _pendingChange = null;
54595             }, 10);
54596           }
54597
54598           section.state = function (val) {
54599             if (!arguments.length) return _state;
54600
54601             if (_state !== val) {
54602               _orderedKeys = [];
54603               _state = val;
54604             }
54605
54606             return section;
54607           };
54608
54609           section.presets = function (val) {
54610             if (!arguments.length) return _presets;
54611             _presets = val;
54612
54613             if (_presets && _presets.length && _presets[0].isFallback()) {
54614               section.disclosureExpanded(true); // don't collapse the disclosure if the mapper used the raw tag editor - #1881
54615             } else if (!_didInteract) {
54616               section.disclosureExpanded(null);
54617             }
54618
54619             return section;
54620           };
54621
54622           section.tags = function (val) {
54623             if (!arguments.length) return _tags;
54624             _tags = val;
54625             return section;
54626           };
54627
54628           section.entityIDs = function (val) {
54629             if (!arguments.length) return _entityIDs;
54630
54631             if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
54632               _entityIDs = val;
54633               _orderedKeys = [];
54634             }
54635
54636             return section;
54637           }; // pass an array of regular expressions to test against the tag key
54638
54639
54640           section.readOnlyTags = function (val) {
54641             if (!arguments.length) return _readOnlyTags;
54642             _readOnlyTags = val;
54643             return section;
54644           };
54645
54646           return utilRebind(section, dispatch$1, 'on');
54647         }
54648
54649         function uiDataEditor(context) {
54650           var dataHeader = uiDataHeader();
54651           var rawTagEditor = uiSectionRawTagEditor('custom-data-tag-editor', context).expandedByDefault(true).readOnlyTags([/./]);
54652
54653           var _datum;
54654
54655           function dataEditor(selection) {
54656             var header = selection.selectAll('.header').data([0]);
54657             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
54658             headerEnter.append('button').attr('class', 'close').on('click', function () {
54659               context.enter(modeBrowse(context));
54660             }).call(svgIcon('#iD-icon-close'));
54661             headerEnter.append('h3').html(_t.html('map_data.title'));
54662             var body = selection.selectAll('.body').data([0]);
54663             body = body.enter().append('div').attr('class', 'body').merge(body);
54664             var editor = body.selectAll('.data-editor').data([0]); // enter/update
54665
54666             editor.enter().append('div').attr('class', 'modal-section data-editor').merge(editor).call(dataHeader.datum(_datum));
54667             var rte = body.selectAll('.raw-tag-editor').data([0]); // enter/update
54668
54669             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);
54670           }
54671
54672           dataEditor.datum = function (val) {
54673             if (!arguments.length) return _datum;
54674             _datum = val;
54675             return this;
54676           };
54677
54678           return dataEditor;
54679         }
54680
54681         function modeSelectData(context, selectedDatum) {
54682           var mode = {
54683             id: 'select-data',
54684             button: 'browse'
54685           };
54686           var keybinding = utilKeybinding('select-data');
54687           var dataEditor = uiDataEditor(context);
54688           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
54689
54690           function selectData(d3_event, drawn) {
54691             var selection = context.surface().selectAll('.layer-mapdata .data' + selectedDatum.__featurehash__);
54692
54693             if (selection.empty()) {
54694               // Return to browse mode if selected DOM elements have
54695               // disappeared because the user moved them out of view..
54696               var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
54697
54698               if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
54699                 context.enter(modeBrowse(context));
54700               }
54701             } else {
54702               selection.classed('selected', true);
54703             }
54704           }
54705
54706           function esc() {
54707             if (context.container().select('.combobox').size()) return;
54708             context.enter(modeBrowse(context));
54709           }
54710
54711           mode.zoomToSelected = function () {
54712             var extent = geoExtent(d3_geoBounds(selectedDatum));
54713             context.map().centerZoomEase(extent.center(), context.map().trimmedExtentZoom(extent));
54714           };
54715
54716           mode.enter = function () {
54717             behaviors.forEach(context.install);
54718             keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
54719             select(document).call(keybinding);
54720             selectData();
54721             var sidebar = context.ui().sidebar;
54722             sidebar.show(dataEditor.datum(selectedDatum)); // expand the sidebar, avoid obscuring the data if needed
54723
54724             var extent = geoExtent(d3_geoBounds(selectedDatum));
54725             sidebar.expand(sidebar.intersects(extent));
54726             context.map().on('drawn.select-data', selectData);
54727           };
54728
54729           mode.exit = function () {
54730             behaviors.forEach(context.uninstall);
54731             select(document).call(keybinding.unbind);
54732             context.surface().selectAll('.layer-mapdata .selected').classed('selected hover', false);
54733             context.map().on('drawn.select-data', null);
54734             context.ui().sidebar.hide();
54735           };
54736
54737           return mode;
54738         }
54739
54740         function uiImproveOsmComments() {
54741           var _qaItem;
54742
54743           function issueComments(selection) {
54744             // make the div immediately so it appears above the buttons
54745             var comments = selection.selectAll('.comments-container').data([0]);
54746             comments = comments.enter().append('div').attr('class', 'comments-container').merge(comments); // must retrieve comments from API before they can be displayed
54747
54748             services.improveOSM.getComments(_qaItem).then(function (d) {
54749               if (!d.comments) return; // nothing to do here
54750
54751               var commentEnter = comments.selectAll('.comment').data(d.comments).enter().append('div').attr('class', 'comment');
54752               commentEnter.append('div').attr('class', 'comment-avatar').call(svgIcon('#iD-icon-avatar', 'comment-avatar-icon'));
54753               var mainEnter = commentEnter.append('div').attr('class', 'comment-main');
54754               var metadataEnter = mainEnter.append('div').attr('class', 'comment-metadata');
54755               metadataEnter.append('div').attr('class', 'comment-author').each(function (d) {
54756                 var osm = services.osm;
54757                 var selection = select(this);
54758
54759                 if (osm && d.username) {
54760                   selection = selection.append('a').attr('class', 'comment-author-link').attr('href', osm.userURL(d.username)).attr('target', '_blank');
54761                 }
54762
54763                 selection.html(function (d) {
54764                   return d.username;
54765                 });
54766               });
54767               metadataEnter.append('div').attr('class', 'comment-date').html(function (d) {
54768                 return _t.html('note.status.commented', {
54769                   when: localeDateString(d.timestamp)
54770                 });
54771               });
54772               mainEnter.append('div').attr('class', 'comment-text').append('p').html(function (d) {
54773                 return d.text;
54774               });
54775             })["catch"](function (err) {
54776               console.log(err); // eslint-disable-line no-console
54777             });
54778           }
54779
54780           function localeDateString(s) {
54781             if (!s) return null;
54782             var options = {
54783               day: 'numeric',
54784               month: 'short',
54785               year: 'numeric'
54786             };
54787             var d = new Date(s * 1000); // timestamp is served in seconds, date takes ms
54788
54789             if (isNaN(d.getTime())) return null;
54790             return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
54791           }
54792
54793           issueComments.issue = function (val) {
54794             if (!arguments.length) return _qaItem;
54795             _qaItem = val;
54796             return issueComments;
54797           };
54798
54799           return issueComments;
54800         }
54801
54802         function uiImproveOsmDetails(context) {
54803           var _qaItem;
54804
54805           function issueDetail(d) {
54806             if (d.desc) return d.desc;
54807             var issueKey = d.issueKey;
54808             d.replacements = d.replacements || {};
54809             d.replacements["default"] = _t.html('inspector.unknown'); // special key `default` works as a fallback string
54810
54811             return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".description"), d.replacements);
54812           }
54813
54814           function improveOsmDetails(selection) {
54815             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
54816               return "".concat(d.id, "-").concat(d.status || 0);
54817             });
54818             details.exit().remove();
54819             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // description
54820
54821             var descriptionEnter = detailsEnter.append('div').attr('class', 'qa-details-subsection');
54822             descriptionEnter.append('h4').html(_t.html('QA.keepRight.detail_description'));
54823             descriptionEnter.append('div').attr('class', 'qa-details-description-text').html(issueDetail); // If there are entity links in the error message..
54824
54825             var relatedEntities = [];
54826             descriptionEnter.selectAll('.error_entity_link, .error_object_link').attr('href', '#').each(function () {
54827               var link = select(this);
54828               var isObjectLink = link.classed('error_object_link');
54829               var entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
54830               var entity = context.hasEntity(entityID);
54831               relatedEntities.push(entityID); // Add click handler
54832
54833               link.on('mouseenter', function () {
54834                 utilHighlightEntities([entityID], true, context);
54835               }).on('mouseleave', function () {
54836                 utilHighlightEntities([entityID], false, context);
54837               }).on('click', function (d3_event) {
54838                 d3_event.preventDefault();
54839                 utilHighlightEntities([entityID], false, context);
54840                 var osmlayer = context.layers().layer('osm');
54841
54842                 if (!osmlayer.enabled()) {
54843                   osmlayer.enabled(true);
54844                 }
54845
54846                 context.map().centerZoom(_qaItem.loc, 20);
54847
54848                 if (entity) {
54849                   context.enter(modeSelect(context, [entityID]));
54850                 } else {
54851                   context.loadEntity(entityID, function () {
54852                     context.enter(modeSelect(context, [entityID]));
54853                   });
54854                 }
54855               }); // Replace with friendly name if possible
54856               // (The entity may not yet be loaded into the graph)
54857
54858               if (entity) {
54859                 var name = utilDisplayName(entity); // try to use common name
54860
54861                 if (!name && !isObjectLink) {
54862                   var preset = _mainPresetIndex.match(entity, context.graph());
54863                   name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
54864                 }
54865
54866                 if (name) {
54867                   this.innerText = name;
54868                 }
54869               }
54870             }); // Don't hide entities related to this error - #5880
54871
54872             context.features().forceVisible(relatedEntities);
54873             context.map().pan([0, 0]); // trigger a redraw
54874           }
54875
54876           improveOsmDetails.issue = function (val) {
54877             if (!arguments.length) return _qaItem;
54878             _qaItem = val;
54879             return improveOsmDetails;
54880           };
54881
54882           return improveOsmDetails;
54883         }
54884
54885         function uiImproveOsmHeader() {
54886           var _qaItem;
54887
54888           function issueTitle(d) {
54889             var issueKey = d.issueKey;
54890             d.replacements = d.replacements || {};
54891             d.replacements["default"] = _t.html('inspector.unknown'); // special key `default` works as a fallback string
54892
54893             return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".title"), d.replacements);
54894           }
54895
54896           function improveOsmHeader(selection) {
54897             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
54898               return "".concat(d.id, "-").concat(d.status || 0);
54899             });
54900             header.exit().remove();
54901             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
54902             var svgEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
54903               return d.id < 0;
54904             }).append('svg').attr('width', '20px').attr('height', '30px').attr('viewbox', '0 0 20 30').attr('class', function (d) {
54905               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
54906             });
54907             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');
54908             svgEnter.append('use').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('transform', 'translate(3.5, 5)').attr('xlink:href', function (d) {
54909               var picon = d.icon;
54910
54911               if (!picon) {
54912                 return '';
54913               } else {
54914                 var isMaki = /^maki-/.test(picon);
54915                 return "#".concat(picon).concat(isMaki ? '-11' : '');
54916               }
54917             });
54918             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
54919           }
54920
54921           improveOsmHeader.issue = function (val) {
54922             if (!arguments.length) return _qaItem;
54923             _qaItem = val;
54924             return improveOsmHeader;
54925           };
54926
54927           return improveOsmHeader;
54928         }
54929
54930         function uiImproveOsmEditor(context) {
54931           var dispatch$1 = dispatch('change');
54932           var qaDetails = uiImproveOsmDetails(context);
54933           var qaComments = uiImproveOsmComments();
54934           var qaHeader = uiImproveOsmHeader();
54935
54936           var _qaItem;
54937
54938           function improveOsmEditor(selection) {
54939             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
54940             headerEnter.append('button').attr('class', 'close').on('click', function () {
54941               return context.enter(modeBrowse(context));
54942             }).call(svgIcon('#iD-icon-close'));
54943             headerEnter.append('h3').html(_t.html('QA.improveOSM.title'));
54944             var body = selection.selectAll('.body').data([0]);
54945             body = body.enter().append('div').attr('class', 'body').merge(body);
54946             var editor = body.selectAll('.qa-editor').data([0]);
54947             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);
54948           }
54949
54950           function improveOsmSaveSection(selection) {
54951             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
54952
54953             var isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
54954             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
54955               return "".concat(d.id, "-").concat(d.status || 0);
54956             }); // exit
54957
54958             saveSection.exit().remove(); // enter
54959
54960             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf');
54961             saveSectionEnter.append('h4').attr('class', '.qa-save-header').html(_t.html('note.newComment'));
54962             saveSectionEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('QA.keepRight.comment_placeholder')).attr('maxlength', 1000).property('value', function (d) {
54963               return d.newComment;
54964             }).call(utilNoAuto).on('input', changeInput).on('blur', changeInput); // update
54965
54966             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
54967
54968             function changeInput() {
54969               var input = select(this);
54970               var val = input.property('value').trim();
54971
54972               if (val === '') {
54973                 val = undefined;
54974               } // store the unsaved comment with the issue itself
54975
54976
54977               _qaItem = _qaItem.update({
54978                 newComment: val
54979               });
54980               var qaService = services.improveOSM;
54981
54982               if (qaService) {
54983                 qaService.replaceItem(_qaItem);
54984               }
54985
54986               saveSection.call(qaSaveButtons);
54987             }
54988           }
54989
54990           function qaSaveButtons(selection) {
54991             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
54992
54993             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
54994               return d.status + d.id;
54995             }); // exit
54996
54997             buttonSection.exit().remove(); // enter
54998
54999             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
55000             buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('QA.keepRight.save_comment'));
55001             buttonEnter.append('button').attr('class', 'button close-button action');
55002             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
55003
55004             buttonSection = buttonSection.merge(buttonEnter);
55005             buttonSection.select('.comment-button').attr('disabled', function (d) {
55006               return d.newComment ? null : true;
55007             }).on('click.comment', function (d3_event, d) {
55008               this.blur(); // avoid keeping focus on the button - #4641
55009
55010               var qaService = services.improveOSM;
55011
55012               if (qaService) {
55013                 qaService.postUpdate(d, function (err, item) {
55014                   return dispatch$1.call('change', item);
55015                 });
55016               }
55017             });
55018             buttonSection.select('.close-button').html(function (d) {
55019               var andComment = d.newComment ? '_comment' : '';
55020               return _t.html("QA.keepRight.close".concat(andComment));
55021             }).on('click.close', function (d3_event, d) {
55022               this.blur(); // avoid keeping focus on the button - #4641
55023
55024               var qaService = services.improveOSM;
55025
55026               if (qaService) {
55027                 d.newStatus = 'SOLVED';
55028                 qaService.postUpdate(d, function (err, item) {
55029                   return dispatch$1.call('change', item);
55030                 });
55031               }
55032             });
55033             buttonSection.select('.ignore-button').html(function (d) {
55034               var andComment = d.newComment ? '_comment' : '';
55035               return _t.html("QA.keepRight.ignore".concat(andComment));
55036             }).on('click.ignore', function (d3_event, d) {
55037               this.blur(); // avoid keeping focus on the button - #4641
55038
55039               var qaService = services.improveOSM;
55040
55041               if (qaService) {
55042                 d.newStatus = 'INVALID';
55043                 qaService.postUpdate(d, function (err, item) {
55044                   return dispatch$1.call('change', item);
55045                 });
55046               }
55047             });
55048           } // NOTE: Don't change method name until UI v3 is merged
55049
55050
55051           improveOsmEditor.error = function (val) {
55052             if (!arguments.length) return _qaItem;
55053             _qaItem = val;
55054             return improveOsmEditor;
55055           };
55056
55057           return utilRebind(improveOsmEditor, dispatch$1, 'on');
55058         }
55059
55060         function uiKeepRightDetails(context) {
55061           var _qaItem;
55062
55063           function issueDetail(d) {
55064             var itemType = d.itemType,
55065                 parentIssueType = d.parentIssueType;
55066             var unknown = _t.html('inspector.unknown');
55067             var replacements = d.replacements || {};
55068             replacements["default"] = unknown; // special key `default` works as a fallback string
55069
55070             var detail = _t.html("QA.keepRight.errorTypes.".concat(itemType, ".description"), replacements);
55071
55072             if (detail === unknown) {
55073               detail = _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".description"), replacements);
55074             }
55075
55076             return detail;
55077           }
55078
55079           function keepRightDetails(selection) {
55080             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
55081               return "".concat(d.id, "-").concat(d.status || 0);
55082             });
55083             details.exit().remove();
55084             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // description
55085
55086             var descriptionEnter = detailsEnter.append('div').attr('class', 'qa-details-subsection');
55087             descriptionEnter.append('h4').html(_t.html('QA.keepRight.detail_description'));
55088             descriptionEnter.append('div').attr('class', 'qa-details-description-text').html(issueDetail); // If there are entity links in the error message..
55089
55090             var relatedEntities = [];
55091             descriptionEnter.selectAll('.error_entity_link, .error_object_link').attr('href', '#').each(function () {
55092               var link = select(this);
55093               var isObjectLink = link.classed('error_object_link');
55094               var entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
55095               var entity = context.hasEntity(entityID);
55096               relatedEntities.push(entityID); // Add click handler
55097
55098               link.on('mouseenter', function () {
55099                 utilHighlightEntities([entityID], true, context);
55100               }).on('mouseleave', function () {
55101                 utilHighlightEntities([entityID], false, context);
55102               }).on('click', function (d3_event) {
55103                 d3_event.preventDefault();
55104                 utilHighlightEntities([entityID], false, context);
55105                 var osmlayer = context.layers().layer('osm');
55106
55107                 if (!osmlayer.enabled()) {
55108                   osmlayer.enabled(true);
55109                 }
55110
55111                 context.map().centerZoomEase(_qaItem.loc, 20);
55112
55113                 if (entity) {
55114                   context.enter(modeSelect(context, [entityID]));
55115                 } else {
55116                   context.loadEntity(entityID, function () {
55117                     context.enter(modeSelect(context, [entityID]));
55118                   });
55119                 }
55120               }); // Replace with friendly name if possible
55121               // (The entity may not yet be loaded into the graph)
55122
55123               if (entity) {
55124                 var name = utilDisplayName(entity); // try to use common name
55125
55126                 if (!name && !isObjectLink) {
55127                   var preset = _mainPresetIndex.match(entity, context.graph());
55128                   name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
55129                 }
55130
55131                 if (name) {
55132                   this.innerText = name;
55133                 }
55134               }
55135             }); // Don't hide entities related to this issue - #5880
55136
55137             context.features().forceVisible(relatedEntities);
55138             context.map().pan([0, 0]); // trigger a redraw
55139           }
55140
55141           keepRightDetails.issue = function (val) {
55142             if (!arguments.length) return _qaItem;
55143             _qaItem = val;
55144             return keepRightDetails;
55145           };
55146
55147           return keepRightDetails;
55148         }
55149
55150         function uiKeepRightHeader() {
55151           var _qaItem;
55152
55153           function issueTitle(d) {
55154             var itemType = d.itemType,
55155                 parentIssueType = d.parentIssueType;
55156             var unknown = _t.html('inspector.unknown');
55157             var replacements = d.replacements || {};
55158             replacements["default"] = unknown; // special key `default` works as a fallback string
55159
55160             var title = _t.html("QA.keepRight.errorTypes.".concat(itemType, ".title"), replacements);
55161
55162             if (title === unknown) {
55163               title = _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".title"), replacements);
55164             }
55165
55166             return title;
55167           }
55168
55169           function keepRightHeader(selection) {
55170             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
55171               return "".concat(d.id, "-").concat(d.status || 0);
55172             });
55173             header.exit().remove();
55174             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
55175             var iconEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
55176               return d.id < 0;
55177             });
55178             iconEnter.append('div').attr('class', function (d) {
55179               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.parentIssueType);
55180             }).call(svgIcon('#iD-icon-bolt', 'qaItem-fill'));
55181             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
55182           }
55183
55184           keepRightHeader.issue = function (val) {
55185             if (!arguments.length) return _qaItem;
55186             _qaItem = val;
55187             return keepRightHeader;
55188           };
55189
55190           return keepRightHeader;
55191         }
55192
55193         function uiViewOnKeepRight() {
55194           var _qaItem;
55195
55196           function viewOnKeepRight(selection) {
55197             var url;
55198
55199             if (services.keepRight && _qaItem instanceof QAItem) {
55200               url = services.keepRight.issueURL(_qaItem);
55201             }
55202
55203             var link = selection.selectAll('.view-on-keepRight').data(url ? [url] : []); // exit
55204
55205             link.exit().remove(); // enter
55206
55207             var linkEnter = link.enter().append('a').attr('class', 'view-on-keepRight').attr('target', '_blank').attr('rel', 'noopener') // security measure
55208             .attr('href', function (d) {
55209               return d;
55210             }).call(svgIcon('#iD-icon-out-link', 'inline'));
55211             linkEnter.append('span').html(_t.html('inspector.view_on_keepRight'));
55212           }
55213
55214           viewOnKeepRight.what = function (val) {
55215             if (!arguments.length) return _qaItem;
55216             _qaItem = val;
55217             return viewOnKeepRight;
55218           };
55219
55220           return viewOnKeepRight;
55221         }
55222
55223         function uiKeepRightEditor(context) {
55224           var dispatch$1 = dispatch('change');
55225           var qaDetails = uiKeepRightDetails(context);
55226           var qaHeader = uiKeepRightHeader();
55227
55228           var _qaItem;
55229
55230           function keepRightEditor(selection) {
55231             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
55232             headerEnter.append('button').attr('class', 'close').on('click', function () {
55233               return context.enter(modeBrowse(context));
55234             }).call(svgIcon('#iD-icon-close'));
55235             headerEnter.append('h3').html(_t.html('QA.keepRight.title'));
55236             var body = selection.selectAll('.body').data([0]);
55237             body = body.enter().append('div').attr('class', 'body').merge(body);
55238             var editor = body.selectAll('.qa-editor').data([0]);
55239             editor.enter().append('div').attr('class', 'modal-section qa-editor').merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(keepRightSaveSection);
55240             var footer = selection.selectAll('.footer').data([0]);
55241             footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnKeepRight().what(_qaItem));
55242           }
55243
55244           function keepRightSaveSection(selection) {
55245             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
55246
55247             var isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
55248             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
55249               return "".concat(d.id, "-").concat(d.status || 0);
55250             }); // exit
55251
55252             saveSection.exit().remove(); // enter
55253
55254             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf');
55255             saveSectionEnter.append('h4').attr('class', '.qa-save-header').html(_t.html('QA.keepRight.comment'));
55256             saveSectionEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('QA.keepRight.comment_placeholder')).attr('maxlength', 1000).property('value', function (d) {
55257               return d.newComment || d.comment;
55258             }).call(utilNoAuto).on('input', changeInput).on('blur', changeInput); // update
55259
55260             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
55261
55262             function changeInput() {
55263               var input = select(this);
55264               var val = input.property('value').trim();
55265
55266               if (val === _qaItem.comment) {
55267                 val = undefined;
55268               } // store the unsaved comment with the issue itself
55269
55270
55271               _qaItem = _qaItem.update({
55272                 newComment: val
55273               });
55274               var qaService = services.keepRight;
55275
55276               if (qaService) {
55277                 qaService.replaceItem(_qaItem); // update keepright cache
55278               }
55279
55280               saveSection.call(qaSaveButtons);
55281             }
55282           }
55283
55284           function qaSaveButtons(selection) {
55285             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
55286
55287             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
55288               return d.status + d.id;
55289             }); // exit
55290
55291             buttonSection.exit().remove(); // enter
55292
55293             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
55294             buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('QA.keepRight.save_comment'));
55295             buttonEnter.append('button').attr('class', 'button close-button action');
55296             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
55297
55298             buttonSection = buttonSection.merge(buttonEnter);
55299             buttonSection.select('.comment-button') // select and propagate data
55300             .attr('disabled', function (d) {
55301               return d.newComment ? null : true;
55302             }).on('click.comment', function (d3_event, d) {
55303               this.blur(); // avoid keeping focus on the button - #4641
55304
55305               var qaService = services.keepRight;
55306
55307               if (qaService) {
55308                 qaService.postUpdate(d, function (err, item) {
55309                   return dispatch$1.call('change', item);
55310                 });
55311               }
55312             });
55313             buttonSection.select('.close-button') // select and propagate data
55314             .html(function (d) {
55315               var andComment = d.newComment ? '_comment' : '';
55316               return _t.html("QA.keepRight.close".concat(andComment));
55317             }).on('click.close', function (d3_event, d) {
55318               this.blur(); // avoid keeping focus on the button - #4641
55319
55320               var qaService = services.keepRight;
55321
55322               if (qaService) {
55323                 d.newStatus = 'ignore_t'; // ignore temporarily (item fixed)
55324
55325                 qaService.postUpdate(d, function (err, item) {
55326                   return dispatch$1.call('change', item);
55327                 });
55328               }
55329             });
55330             buttonSection.select('.ignore-button') // select and propagate data
55331             .html(function (d) {
55332               var andComment = d.newComment ? '_comment' : '';
55333               return _t.html("QA.keepRight.ignore".concat(andComment));
55334             }).on('click.ignore', function (d3_event, d) {
55335               this.blur(); // avoid keeping focus on the button - #4641
55336
55337               var qaService = services.keepRight;
55338
55339               if (qaService) {
55340                 d.newStatus = 'ignore'; // ignore permanently (false positive)
55341
55342                 qaService.postUpdate(d, function (err, item) {
55343                   return dispatch$1.call('change', item);
55344                 });
55345               }
55346             });
55347           } // NOTE: Don't change method name until UI v3 is merged
55348
55349
55350           keepRightEditor.error = function (val) {
55351             if (!arguments.length) return _qaItem;
55352             _qaItem = val;
55353             return keepRightEditor;
55354           };
55355
55356           return utilRebind(keepRightEditor, dispatch$1, 'on');
55357         }
55358
55359         function uiOsmoseDetails(context) {
55360           var _qaItem;
55361
55362           function issueString(d, type) {
55363             if (!d) return ''; // Issue strings are cached from Osmose API
55364
55365             var s = services.osmose.getStrings(d.itemType);
55366             return type in s ? s[type] : '';
55367           }
55368
55369           function osmoseDetails(selection) {
55370             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
55371               return "".concat(d.id, "-").concat(d.status || 0);
55372             });
55373             details.exit().remove();
55374             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // Description
55375
55376             if (issueString(_qaItem, 'detail')) {
55377               var div = detailsEnter.append('div').attr('class', 'qa-details-subsection');
55378               div.append('h4').html(_t.html('QA.keepRight.detail_description'));
55379               div.append('p').attr('class', 'qa-details-description-text').html(function (d) {
55380                 return issueString(d, 'detail');
55381               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
55382             } // Elements (populated later as data is requested)
55383
55384
55385             var detailsDiv = detailsEnter.append('div').attr('class', 'qa-details-subsection');
55386             var elemsDiv = detailsEnter.append('div').attr('class', 'qa-details-subsection'); // Suggested Fix (mustn't exist for every issue type)
55387
55388             if (issueString(_qaItem, 'fix')) {
55389               var _div = detailsEnter.append('div').attr('class', 'qa-details-subsection');
55390
55391               _div.append('h4').html(_t.html('QA.osmose.fix_title'));
55392
55393               _div.append('p').html(function (d) {
55394                 return issueString(d, 'fix');
55395               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
55396             } // Common Pitfalls (mustn't exist for every issue type)
55397
55398
55399             if (issueString(_qaItem, 'trap')) {
55400               var _div2 = detailsEnter.append('div').attr('class', 'qa-details-subsection');
55401
55402               _div2.append('h4').html(_t.html('QA.osmose.trap_title'));
55403
55404               _div2.append('p').html(function (d) {
55405                 return issueString(d, 'trap');
55406               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
55407             } // Save current item to check if UI changed by time request resolves
55408
55409
55410             var thisItem = _qaItem;
55411             services.osmose.loadIssueDetail(_qaItem).then(function (d) {
55412               // No details to add if there are no associated issue elements
55413               if (!d.elems || d.elems.length === 0) return; // Do nothing if UI has moved on by the time this resolves
55414
55415               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
55416
55417               if (d.detail) {
55418                 detailsDiv.append('h4').html(_t.html('QA.osmose.detail_title'));
55419                 detailsDiv.append('p').html(function (d) {
55420                   return d.detail;
55421                 }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
55422               } // Create list of linked issue elements
55423
55424
55425               elemsDiv.append('h4').html(_t.html('QA.osmose.elems_title'));
55426               elemsDiv.append('ul').selectAll('li').data(d.elems).enter().append('li').append('a').attr('href', '#').attr('class', 'error_entity_link').html(function (d) {
55427                 return d;
55428               }).each(function () {
55429                 var link = select(this);
55430                 var entityID = this.textContent;
55431                 var entity = context.hasEntity(entityID); // Add click handler
55432
55433                 link.on('mouseenter', function () {
55434                   utilHighlightEntities([entityID], true, context);
55435                 }).on('mouseleave', function () {
55436                   utilHighlightEntities([entityID], false, context);
55437                 }).on('click', function (d3_event) {
55438                   d3_event.preventDefault();
55439                   utilHighlightEntities([entityID], false, context);
55440                   var osmlayer = context.layers().layer('osm');
55441
55442                   if (!osmlayer.enabled()) {
55443                     osmlayer.enabled(true);
55444                   }
55445
55446                   context.map().centerZoom(d.loc, 20);
55447
55448                   if (entity) {
55449                     context.enter(modeSelect(context, [entityID]));
55450                   } else {
55451                     context.loadEntity(entityID, function () {
55452                       context.enter(modeSelect(context, [entityID]));
55453                     });
55454                   }
55455                 }); // Replace with friendly name if possible
55456                 // (The entity may not yet be loaded into the graph)
55457
55458                 if (entity) {
55459                   var name = utilDisplayName(entity); // try to use common name
55460
55461                   if (!name) {
55462                     var preset = _mainPresetIndex.match(entity, context.graph());
55463                     name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
55464                   }
55465
55466                   if (name) {
55467                     this.innerText = name;
55468                   }
55469                 }
55470               }); // Don't hide entities related to this issue - #5880
55471
55472               context.features().forceVisible(d.elems);
55473               context.map().pan([0, 0]); // trigger a redraw
55474             })["catch"](function (err) {
55475               console.log(err); // eslint-disable-line no-console
55476             });
55477           }
55478
55479           osmoseDetails.issue = function (val) {
55480             if (!arguments.length) return _qaItem;
55481             _qaItem = val;
55482             return osmoseDetails;
55483           };
55484
55485           return osmoseDetails;
55486         }
55487
55488         function uiOsmoseHeader() {
55489           var _qaItem;
55490
55491           function issueTitle(d) {
55492             var unknown = _t('inspector.unknown');
55493             if (!d) return unknown; // Issue titles supplied by Osmose
55494
55495             var s = services.osmose.getStrings(d.itemType);
55496             return 'title' in s ? s.title : unknown;
55497           }
55498
55499           function osmoseHeader(selection) {
55500             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
55501               return "".concat(d.id, "-").concat(d.status || 0);
55502             });
55503             header.exit().remove();
55504             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
55505             var svgEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
55506               return d.id < 0;
55507             }).append('svg').attr('width', '20px').attr('height', '30px').attr('viewbox', '0 0 20 30').attr('class', function (d) {
55508               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
55509             });
55510             svgEnter.append('polygon').attr('fill', function (d) {
55511               return services.osmose.getColor(d.item);
55512             }).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');
55513             svgEnter.append('use').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('transform', 'translate(3.5, 5)').attr('xlink:href', function (d) {
55514               var picon = d.icon;
55515
55516               if (!picon) {
55517                 return '';
55518               } else {
55519                 var isMaki = /^maki-/.test(picon);
55520                 return "#".concat(picon).concat(isMaki ? '-11' : '');
55521               }
55522             });
55523             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
55524           }
55525
55526           osmoseHeader.issue = function (val) {
55527             if (!arguments.length) return _qaItem;
55528             _qaItem = val;
55529             return osmoseHeader;
55530           };
55531
55532           return osmoseHeader;
55533         }
55534
55535         function uiViewOnOsmose() {
55536           var _qaItem;
55537
55538           function viewOnOsmose(selection) {
55539             var url;
55540
55541             if (services.osmose && _qaItem instanceof QAItem) {
55542               url = services.osmose.itemURL(_qaItem);
55543             }
55544
55545             var link = selection.selectAll('.view-on-osmose').data(url ? [url] : []); // exit
55546
55547             link.exit().remove(); // enter
55548
55549             var linkEnter = link.enter().append('a').attr('class', 'view-on-osmose').attr('target', '_blank').attr('rel', 'noopener') // security measure
55550             .attr('href', function (d) {
55551               return d;
55552             }).call(svgIcon('#iD-icon-out-link', 'inline'));
55553             linkEnter.append('span').html(_t.html('inspector.view_on_osmose'));
55554           }
55555
55556           viewOnOsmose.what = function (val) {
55557             if (!arguments.length) return _qaItem;
55558             _qaItem = val;
55559             return viewOnOsmose;
55560           };
55561
55562           return viewOnOsmose;
55563         }
55564
55565         function uiOsmoseEditor(context) {
55566           var dispatch$1 = dispatch('change');
55567           var qaDetails = uiOsmoseDetails(context);
55568           var qaHeader = uiOsmoseHeader();
55569
55570           var _qaItem;
55571
55572           function osmoseEditor(selection) {
55573             var header = selection.selectAll('.header').data([0]);
55574             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
55575             headerEnter.append('button').attr('class', 'close').on('click', function () {
55576               return context.enter(modeBrowse(context));
55577             }).call(svgIcon('#iD-icon-close'));
55578             headerEnter.append('h3').html(_t.html('QA.osmose.title'));
55579             var body = selection.selectAll('.body').data([0]);
55580             body = body.enter().append('div').attr('class', 'body').merge(body);
55581             var editor = body.selectAll('.qa-editor').data([0]);
55582             editor.enter().append('div').attr('class', 'modal-section qa-editor').merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(osmoseSaveSection);
55583             var footer = selection.selectAll('.footer').data([0]);
55584             footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnOsmose().what(_qaItem));
55585           }
55586
55587           function osmoseSaveSection(selection) {
55588             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
55589
55590             var isShown = _qaItem && isSelected;
55591             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
55592               return "".concat(d.id, "-").concat(d.status || 0);
55593             }); // exit
55594
55595             saveSection.exit().remove(); // enter
55596
55597             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf'); // update
55598
55599             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
55600           }
55601
55602           function qaSaveButtons(selection) {
55603             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
55604
55605             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
55606               return d.status + d.id;
55607             }); // exit
55608
55609             buttonSection.exit().remove(); // enter
55610
55611             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
55612             buttonEnter.append('button').attr('class', 'button close-button action');
55613             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
55614
55615             buttonSection = buttonSection.merge(buttonEnter);
55616             buttonSection.select('.close-button').html(_t.html('QA.keepRight.close')).on('click.close', function (d3_event, d) {
55617               this.blur(); // avoid keeping focus on the button - #4641
55618
55619               var qaService = services.osmose;
55620
55621               if (qaService) {
55622                 d.newStatus = 'done';
55623                 qaService.postUpdate(d, function (err, item) {
55624                   return dispatch$1.call('change', item);
55625                 });
55626               }
55627             });
55628             buttonSection.select('.ignore-button').html(_t.html('QA.keepRight.ignore')).on('click.ignore', function (d3_event, d) {
55629               this.blur(); // avoid keeping focus on the button - #4641
55630
55631               var qaService = services.osmose;
55632
55633               if (qaService) {
55634                 d.newStatus = 'false';
55635                 qaService.postUpdate(d, function (err, item) {
55636                   return dispatch$1.call('change', item);
55637                 });
55638               }
55639             });
55640           } // NOTE: Don't change method name until UI v3 is merged
55641
55642
55643           osmoseEditor.error = function (val) {
55644             if (!arguments.length) return _qaItem;
55645             _qaItem = val;
55646             return osmoseEditor;
55647           };
55648
55649           return utilRebind(osmoseEditor, dispatch$1, 'on');
55650         }
55651
55652         function modeSelectError(context, selectedErrorID, selectedErrorService) {
55653           var mode = {
55654             id: 'select-error',
55655             button: 'browse'
55656           };
55657           var keybinding = utilKeybinding('select-error');
55658           var errorService = services[selectedErrorService];
55659           var errorEditor;
55660
55661           switch (selectedErrorService) {
55662             case 'improveOSM':
55663               errorEditor = uiImproveOsmEditor(context).on('change', function () {
55664                 context.map().pan([0, 0]); // trigger a redraw
55665
55666                 var error = checkSelectedID();
55667                 if (!error) return;
55668                 context.ui().sidebar.show(errorEditor.error(error));
55669               });
55670               break;
55671
55672             case 'keepRight':
55673               errorEditor = uiKeepRightEditor(context).on('change', function () {
55674                 context.map().pan([0, 0]); // trigger a redraw
55675
55676                 var error = checkSelectedID();
55677                 if (!error) return;
55678                 context.ui().sidebar.show(errorEditor.error(error));
55679               });
55680               break;
55681
55682             case 'osmose':
55683               errorEditor = uiOsmoseEditor(context).on('change', function () {
55684                 context.map().pan([0, 0]); // trigger a redraw
55685
55686                 var error = checkSelectedID();
55687                 if (!error) return;
55688                 context.ui().sidebar.show(errorEditor.error(error));
55689               });
55690               break;
55691           }
55692
55693           var behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
55694
55695           function checkSelectedID() {
55696             if (!errorService) return;
55697             var error = errorService.getError(selectedErrorID);
55698
55699             if (!error) {
55700               context.enter(modeBrowse(context));
55701             }
55702
55703             return error;
55704           }
55705
55706           mode.zoomToSelected = function () {
55707             if (!errorService) return;
55708             var error = errorService.getError(selectedErrorID);
55709
55710             if (error) {
55711               context.map().centerZoomEase(error.loc, 20);
55712             }
55713           };
55714
55715           mode.enter = function () {
55716             var error = checkSelectedID();
55717             if (!error) return;
55718             behaviors.forEach(context.install);
55719             keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
55720             select(document).call(keybinding);
55721             selectError();
55722             var sidebar = context.ui().sidebar;
55723             sidebar.show(errorEditor.error(error));
55724             context.map().on('drawn.select-error', selectError); // class the error as selected, or return to browse mode if the error is gone
55725
55726             function selectError(d3_event, drawn) {
55727               if (!checkSelectedID()) return;
55728               var selection = context.surface().selectAll('.itemId-' + selectedErrorID + '.' + selectedErrorService);
55729
55730               if (selection.empty()) {
55731                 // Return to browse mode if selected DOM elements have
55732                 // disappeared because the user moved them out of view..
55733                 var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
55734
55735                 if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
55736                   context.enter(modeBrowse(context));
55737                 }
55738               } else {
55739                 selection.classed('selected', true);
55740                 context.selectedErrorID(selectedErrorID);
55741               }
55742             }
55743
55744             function esc() {
55745               if (context.container().select('.combobox').size()) return;
55746               context.enter(modeBrowse(context));
55747             }
55748           };
55749
55750           mode.exit = function () {
55751             behaviors.forEach(context.uninstall);
55752             select(document).call(keybinding.unbind);
55753             context.surface().selectAll('.qaItem.selected').classed('selected hover', false);
55754             context.map().on('drawn.select-error', null);
55755             context.ui().sidebar.hide();
55756             context.selectedErrorID(null);
55757             context.features().forceVisible([]);
55758           };
55759
55760           return mode;
55761         }
55762
55763         function behaviorSelect(context) {
55764           var _tolerancePx = 4; // see also behaviorDrag
55765
55766           var _lastMouseEvent = null;
55767           var _showMenu = false;
55768           var _downPointers = {};
55769           var _longPressTimeout = null;
55770           var _lastInteractionType = null; // the id of the down pointer that's enabling multiselection while down
55771
55772           var _multiselectionPointerId = null; // use pointer events on supported platforms; fallback to mouse events
55773
55774           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
55775
55776           function keydown(d3_event) {
55777             if (d3_event.keyCode === 32) {
55778               // don't react to spacebar events during text input
55779               var activeNode = document.activeElement;
55780               if (activeNode && new Set(['INPUT', 'TEXTAREA']).has(activeNode.nodeName)) return;
55781             }
55782
55783             if (d3_event.keyCode === 93 || // context menu key
55784             d3_event.keyCode === 32) {
55785               // spacebar
55786               d3_event.preventDefault();
55787             }
55788
55789             if (d3_event.repeat) return; // ignore repeated events for held keys
55790             // if any key is pressed the user is probably doing something other than long-pressing
55791
55792             cancelLongPress();
55793
55794             if (d3_event.shiftKey) {
55795               context.surface().classed('behavior-multiselect', true);
55796             }
55797
55798             if (d3_event.keyCode === 32) {
55799               // spacebar
55800               if (!_downPointers.spacebar && _lastMouseEvent) {
55801                 cancelLongPress();
55802                 _longPressTimeout = window.setTimeout(didLongPress, 500, 'spacebar', 'spacebar');
55803                 _downPointers.spacebar = {
55804                   firstEvent: _lastMouseEvent,
55805                   lastEvent: _lastMouseEvent
55806                 };
55807               }
55808             }
55809           }
55810
55811           function keyup(d3_event) {
55812             cancelLongPress();
55813
55814             if (!d3_event.shiftKey) {
55815               context.surface().classed('behavior-multiselect', false);
55816             }
55817
55818             if (d3_event.keyCode === 93) {
55819               // context menu key
55820               d3_event.preventDefault();
55821               _lastInteractionType = 'menukey';
55822               contextmenu(d3_event);
55823             } else if (d3_event.keyCode === 32) {
55824               // spacebar
55825               var pointer = _downPointers.spacebar;
55826
55827               if (pointer) {
55828                 delete _downPointers.spacebar;
55829                 if (pointer.done) return;
55830                 d3_event.preventDefault();
55831                 _lastInteractionType = 'spacebar';
55832                 click(pointer.firstEvent, pointer.lastEvent, 'spacebar');
55833               }
55834             }
55835           }
55836
55837           function pointerdown(d3_event) {
55838             var id = (d3_event.pointerId || 'mouse').toString();
55839             cancelLongPress();
55840             if (d3_event.buttons && d3_event.buttons !== 1) return;
55841             context.ui().closeEditMenu();
55842             _longPressTimeout = window.setTimeout(didLongPress, 500, id, 'longdown-' + (d3_event.pointerType || 'mouse'));
55843             _downPointers[id] = {
55844               firstEvent: d3_event,
55845               lastEvent: d3_event
55846             };
55847           }
55848
55849           function didLongPress(id, interactionType) {
55850             var pointer = _downPointers[id];
55851             if (!pointer) return;
55852
55853             for (var i in _downPointers) {
55854               // don't allow this or any currently down pointer to trigger another click
55855               _downPointers[i].done = true;
55856             } // treat long presses like right-clicks
55857
55858
55859             _longPressTimeout = null;
55860             _lastInteractionType = interactionType;
55861             _showMenu = true;
55862             click(pointer.firstEvent, pointer.lastEvent, id);
55863           }
55864
55865           function pointermove(d3_event) {
55866             var id = (d3_event.pointerId || 'mouse').toString();
55867
55868             if (_downPointers[id]) {
55869               _downPointers[id].lastEvent = d3_event;
55870             }
55871
55872             if (!d3_event.pointerType || d3_event.pointerType === 'mouse') {
55873               _lastMouseEvent = d3_event;
55874
55875               if (_downPointers.spacebar) {
55876                 _downPointers.spacebar.lastEvent = d3_event;
55877               }
55878             }
55879           }
55880
55881           function pointerup(d3_event) {
55882             var id = (d3_event.pointerId || 'mouse').toString();
55883             var pointer = _downPointers[id];
55884             if (!pointer) return;
55885             delete _downPointers[id];
55886
55887             if (_multiselectionPointerId === id) {
55888               _multiselectionPointerId = null;
55889             }
55890
55891             if (pointer.done) return;
55892             click(pointer.firstEvent, d3_event, id);
55893           }
55894
55895           function pointercancel(d3_event) {
55896             var id = (d3_event.pointerId || 'mouse').toString();
55897             if (!_downPointers[id]) return;
55898             delete _downPointers[id];
55899
55900             if (_multiselectionPointerId === id) {
55901               _multiselectionPointerId = null;
55902             }
55903           }
55904
55905           function contextmenu(d3_event) {
55906             d3_event.preventDefault();
55907
55908             if (!+d3_event.clientX && !+d3_event.clientY) {
55909               if (_lastMouseEvent) {
55910                 d3_event.sourceEvent = _lastMouseEvent;
55911               } else {
55912                 return;
55913               }
55914             } else {
55915               _lastMouseEvent = d3_event;
55916               _lastInteractionType = 'rightclick';
55917             }
55918
55919             _showMenu = true;
55920             click(d3_event, d3_event);
55921           }
55922
55923           function click(firstEvent, lastEvent, pointerId) {
55924             cancelLongPress();
55925             var mapNode = context.container().select('.main-map').node(); // Use the `main-map` coordinate system since the surface and supersurface
55926             // are transformed when drag-panning.
55927
55928             var pointGetter = utilFastMouse(mapNode);
55929             var p1 = pointGetter(firstEvent);
55930             var p2 = pointGetter(lastEvent);
55931             var dist = geoVecLength(p1, p2);
55932
55933             if (dist > _tolerancePx || !mapContains(lastEvent)) {
55934               resetProperties();
55935               return;
55936             }
55937
55938             var targetDatum = lastEvent.target.__data__;
55939             var multiselectEntityId;
55940
55941             if (!_multiselectionPointerId) {
55942               // If a different pointer than the one triggering this click is down on a
55943               // feature, treat this and all future clicks as multiselection until that
55944               // pointer is raised.
55945               var selectPointerInfo = pointerDownOnSelection(pointerId);
55946
55947               if (selectPointerInfo) {
55948                 _multiselectionPointerId = selectPointerInfo.pointerId; // if the other feature isn't selected yet, make sure we select it
55949
55950                 multiselectEntityId = !selectPointerInfo.selected && selectPointerInfo.entityId;
55951                 _downPointers[selectPointerInfo.pointerId].done = true;
55952               }
55953             } // support multiselect if data is already selected
55954
55955
55956             var isMultiselect = context.mode().id === 'select' && ( // and shift key is down
55957             lastEvent && lastEvent.shiftKey || // or we're lasso-selecting
55958             context.surface().select('.lasso').node() || // or a pointer is down over a selected feature
55959             _multiselectionPointerId && !multiselectEntityId);
55960
55961             processClick(targetDatum, isMultiselect, p2, multiselectEntityId);
55962
55963             function mapContains(event) {
55964               var rect = mapNode.getBoundingClientRect();
55965               return event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
55966             }
55967
55968             function pointerDownOnSelection(skipPointerId) {
55969               var mode = context.mode();
55970               var selectedIDs = mode.id === 'select' ? mode.selectedIDs() : [];
55971
55972               for (var pointerId in _downPointers) {
55973                 if (pointerId === 'spacebar' || pointerId === skipPointerId) continue;
55974                 var pointerInfo = _downPointers[pointerId];
55975                 var p1 = pointGetter(pointerInfo.firstEvent);
55976                 var p2 = pointGetter(pointerInfo.lastEvent);
55977                 if (geoVecLength(p1, p2) > _tolerancePx) continue;
55978                 var datum = pointerInfo.firstEvent.target.__data__;
55979                 var entity = datum && datum.properties && datum.properties.entity || datum;
55980                 if (context.graph().hasEntity(entity.id)) return {
55981                   pointerId: pointerId,
55982                   entityId: entity.id,
55983                   selected: selectedIDs.indexOf(entity.id) !== -1
55984                 };
55985               }
55986
55987               return null;
55988             }
55989           }
55990
55991           function processClick(datum, isMultiselect, point, alsoSelectId) {
55992             var mode = context.mode();
55993             var showMenu = _showMenu;
55994             var interactionType = _lastInteractionType;
55995             var entity = datum && datum.properties && datum.properties.entity;
55996             if (entity) datum = entity;
55997
55998             if (datum && datum.type === 'midpoint') {
55999               // treat targeting midpoints as if targeting the parent way
56000               datum = datum.parents[0];
56001             }
56002
56003             var newMode;
56004
56005             if (datum instanceof osmEntity) {
56006               // targeting an entity
56007               var selectedIDs = context.selectedIDs();
56008               context.selectedNoteID(null);
56009               context.selectedErrorID(null);
56010
56011               if (!isMultiselect) {
56012                 // don't change the selection if we're toggling the menu atop a multiselection
56013                 if (!showMenu || selectedIDs.length <= 1 || selectedIDs.indexOf(datum.id) === -1) {
56014                   if (alsoSelectId === datum.id) alsoSelectId = null;
56015                   selectedIDs = (alsoSelectId ? [alsoSelectId] : []).concat([datum.id]); // always enter modeSelect even if the entity is already
56016                   // selected since listeners may expect `context.enter` events,
56017                   // e.g. in the walkthrough
56018
56019                   newMode = mode.id === 'select' ? mode.selectedIDs(selectedIDs) : modeSelect(context, selectedIDs).selectBehavior(behavior);
56020                   context.enter(newMode);
56021                 }
56022               } else {
56023                 if (selectedIDs.indexOf(datum.id) !== -1) {
56024                   // clicked entity is already in the selectedIDs list..
56025                   if (!showMenu) {
56026                     // deselect clicked entity, then reenter select mode or return to browse mode..
56027                     selectedIDs = selectedIDs.filter(function (id) {
56028                       return id !== datum.id;
56029                     });
56030                     newMode = selectedIDs.length ? mode.selectedIDs(selectedIDs) : modeBrowse(context).selectBehavior(behavior);
56031                     context.enter(newMode);
56032                   }
56033                 } else {
56034                   // clicked entity is not in the selected list, add it..
56035                   selectedIDs = selectedIDs.concat([datum.id]);
56036                   newMode = mode.selectedIDs(selectedIDs);
56037                   context.enter(newMode);
56038                 }
56039               }
56040             } else if (datum && datum.__featurehash__ && !isMultiselect) {
56041               // targeting custom data
56042               context.selectedNoteID(null).enter(modeSelectData(context, datum));
56043             } else if (datum instanceof osmNote && !isMultiselect) {
56044               // targeting a note
56045               context.selectedNoteID(datum.id).enter(modeSelectNote(context, datum.id));
56046             } else if (datum instanceof QAItem & !isMultiselect) {
56047               // targeting an external QA issue
56048               context.selectedErrorID(datum.id).enter(modeSelectError(context, datum.id, datum.service));
56049             } else {
56050               // targeting nothing
56051               context.selectedNoteID(null);
56052               context.selectedErrorID(null);
56053
56054               if (!isMultiselect && mode.id !== 'browse') {
56055                 context.enter(modeBrowse(context));
56056               }
56057             }
56058
56059             context.ui().closeEditMenu(); // always request to show the edit menu in case the mode needs it
56060
56061             if (showMenu) context.ui().showEditMenu(point, interactionType);
56062             resetProperties();
56063           }
56064
56065           function cancelLongPress() {
56066             if (_longPressTimeout) window.clearTimeout(_longPressTimeout);
56067             _longPressTimeout = null;
56068           }
56069
56070           function resetProperties() {
56071             cancelLongPress();
56072             _showMenu = false;
56073             _lastInteractionType = null; // don't reset _lastMouseEvent since it might still be useful
56074           }
56075
56076           function behavior(selection) {
56077             resetProperties();
56078             _lastMouseEvent = context.map().lastPointerEvent();
56079             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) {
56080               // Edge and IE really like to show the contextmenu on the
56081               // menubar when user presses a keyboard menu button
56082               // even after we've already preventdefaulted the key event.
56083               var e = d3_event;
56084
56085               if (+e.clientX === 0 && +e.clientY === 0) {
56086                 d3_event.preventDefault();
56087               }
56088             });
56089             selection.on(_pointerPrefix + 'down.select', pointerdown).on('contextmenu.select', contextmenu);
56090             /*if (d3_event && d3_event.shiftKey) {
56091                 context.surface()
56092                     .classed('behavior-multiselect', true);
56093             }*/
56094           }
56095
56096           behavior.off = function (selection) {
56097             cancelLongPress();
56098             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);
56099             selection.on(_pointerPrefix + 'down.select', null).on('contextmenu.select', null);
56100             context.surface().classed('behavior-multiselect', false);
56101           };
56102
56103           return behavior;
56104         }
56105
56106         function behaviorDrawWay(context, wayID, mode, startGraph) {
56107           var dispatch$1 = dispatch('rejectedSelfIntersection');
56108           var behavior = behaviorDraw(context); // Must be set by `drawWay.nodeIndex` before each install of this behavior.
56109
56110           var _nodeIndex;
56111
56112           var _origWay;
56113
56114           var _wayGeometry;
56115
56116           var _headNodeID;
56117
56118           var _annotation;
56119
56120           var _pointerHasMoved = false; // The osmNode to be placed.
56121           // This is temporary and just follows the mouse cursor until an "add" event occurs.
56122
56123           var _drawNode;
56124
56125           var _didResolveTempEdit = false;
56126
56127           function createDrawNode(loc) {
56128             // don't make the draw node until we actually need it
56129             _drawNode = osmNode({
56130               loc: loc
56131             });
56132             context.pauseChangeDispatch();
56133             context.replace(function actionAddDrawNode(graph) {
56134               // add the draw node to the graph and insert it into the way
56135               var way = graph.entity(wayID);
56136               return graph.replace(_drawNode).replace(way.addNode(_drawNode.id, _nodeIndex));
56137             }, _annotation);
56138             context.resumeChangeDispatch();
56139             setActiveElements();
56140           }
56141
56142           function removeDrawNode() {
56143             context.pauseChangeDispatch();
56144             context.replace(function actionDeleteDrawNode(graph) {
56145               var way = graph.entity(wayID);
56146               return graph.replace(way.removeNode(_drawNode.id)).remove(_drawNode);
56147             }, _annotation);
56148             _drawNode = undefined;
56149             context.resumeChangeDispatch();
56150           }
56151
56152           function keydown(d3_event) {
56153             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
56154               if (context.surface().classed('nope')) {
56155                 context.surface().classed('nope-suppressed', true);
56156               }
56157
56158               context.surface().classed('nope', false).classed('nope-disabled', true);
56159             }
56160           }
56161
56162           function keyup(d3_event) {
56163             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
56164               if (context.surface().classed('nope-suppressed')) {
56165                 context.surface().classed('nope', true);
56166               }
56167
56168               context.surface().classed('nope-suppressed', false).classed('nope-disabled', false);
56169             }
56170           }
56171
56172           function allowsVertex(d) {
56173             return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
56174           } // related code
56175           // - `mode/drag_node.js`     `doMove()`
56176           // - `behavior/draw.js`      `click()`
56177           // - `behavior/draw_way.js`  `move()`
56178
56179
56180           function move(d3_event, datum) {
56181             var loc = context.map().mouseCoordinates();
56182             if (!_drawNode) createDrawNode(loc);
56183             context.surface().classed('nope-disabled', d3_event.altKey);
56184             var targetLoc = datum && datum.properties && datum.properties.entity && allowsVertex(datum.properties.entity) && datum.properties.entity.loc;
56185             var targetNodes = datum && datum.properties && datum.properties.nodes;
56186
56187             if (targetLoc) {
56188               // snap to node/vertex - a point target with `.loc`
56189               loc = targetLoc;
56190             } else if (targetNodes) {
56191               // snap to way - a line target with `.nodes`
56192               var choice = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, _drawNode.id);
56193
56194               if (choice) {
56195                 loc = choice.loc;
56196               }
56197             }
56198
56199             context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
56200             _drawNode = context.entity(_drawNode.id);
56201             checkGeometry(true
56202             /* includeDrawNode */
56203             );
56204           } // Check whether this edit causes the geometry to break.
56205           // If so, class the surface with a nope cursor.
56206           // `includeDrawNode` - Only check the relevant line segments if finishing drawing
56207
56208
56209           function checkGeometry(includeDrawNode) {
56210             var nopeDisabled = context.surface().classed('nope-disabled');
56211             var isInvalid = isInvalidGeometry(includeDrawNode);
56212
56213             if (nopeDisabled) {
56214               context.surface().classed('nope', false).classed('nope-suppressed', isInvalid);
56215             } else {
56216               context.surface().classed('nope', isInvalid).classed('nope-suppressed', false);
56217             }
56218           }
56219
56220           function isInvalidGeometry(includeDrawNode) {
56221             var testNode = _drawNode; // we only need to test the single way we're drawing
56222
56223             var parentWay = context.graph().entity(wayID);
56224             var nodes = context.graph().childNodes(parentWay).slice(); // shallow copy
56225
56226             if (includeDrawNode) {
56227               if (parentWay.isClosed()) {
56228                 // don't test the last segment for closed ways - #4655
56229                 // (still test the first segment)
56230                 nodes.pop();
56231               }
56232             } else {
56233               // discount the draw node
56234               if (parentWay.isClosed()) {
56235                 if (nodes.length < 3) return false;
56236                 if (_drawNode) nodes.splice(-2, 1);
56237                 testNode = nodes[nodes.length - 2];
56238               } else {
56239                 // there's nothing we need to test if we ignore the draw node on open ways
56240                 return false;
56241               }
56242             }
56243
56244             return testNode && geoHasSelfIntersections(nodes, testNode.id);
56245           }
56246
56247           function undone() {
56248             // undoing removed the temp edit
56249             _didResolveTempEdit = true;
56250             context.pauseChangeDispatch();
56251             var nextMode;
56252
56253             if (context.graph() === startGraph) {
56254               // We've undone back to the initial state before we started drawing.
56255               // Just exit the draw mode without undoing whatever we did before
56256               // we entered the draw mode.
56257               nextMode = modeSelect(context, [wayID]);
56258             } else {
56259               // The `undo` only removed the temporary edit, so here we have to
56260               // manually undo to actually remove the last node we added. We can't
56261               // use the `undo` function since the initial "add" graph doesn't have
56262               // an annotation and so cannot be undone to.
56263               context.pop(1); // continue drawing
56264
56265               nextMode = mode;
56266             } // clear the redo stack by adding and removing a blank edit
56267
56268
56269             context.perform(actionNoop());
56270             context.pop(1);
56271             context.resumeChangeDispatch();
56272             context.enter(nextMode);
56273           }
56274
56275           function setActiveElements() {
56276             if (!_drawNode) return;
56277             context.surface().selectAll('.' + _drawNode.id).classed('active', true);
56278           }
56279
56280           function resetToStartGraph() {
56281             while (context.graph() !== startGraph) {
56282               context.pop();
56283             }
56284           }
56285
56286           var drawWay = function drawWay(surface) {
56287             _drawNode = undefined;
56288             _didResolveTempEdit = false;
56289             _origWay = context.entity(wayID);
56290             _headNodeID = typeof _nodeIndex === 'number' ? _origWay.nodes[_nodeIndex] : _origWay.isClosed() ? _origWay.nodes[_origWay.nodes.length - 2] : _origWay.nodes[_origWay.nodes.length - 1];
56291             _wayGeometry = _origWay.geometry(context.graph());
56292             _annotation = _t((_origWay.nodes.length === (_origWay.isClosed() ? 2 : 1) ? 'operations.start.annotation.' : 'operations.continue.annotation.') + _wayGeometry);
56293             _pointerHasMoved = false; // Push an annotated state for undo to return back to.
56294             // We must make sure to replace or remove it later.
56295
56296             context.pauseChangeDispatch();
56297             context.perform(actionNoop(), _annotation);
56298             context.resumeChangeDispatch();
56299             behavior.hover().initialNodeID(_headNodeID);
56300             behavior.on('move', function () {
56301               _pointerHasMoved = true;
56302               move.apply(this, arguments);
56303             }).on('down', function () {
56304               move.apply(this, arguments);
56305             }).on('downcancel', function () {
56306               if (_drawNode) removeDrawNode();
56307             }).on('click', drawWay.add).on('clickWay', drawWay.addWay).on('clickNode', drawWay.addNode).on('undo', context.undo).on('cancel', drawWay.cancel).on('finish', drawWay.finish);
56308             select(window).on('keydown.drawWay', keydown).on('keyup.drawWay', keyup);
56309             context.map().dblclickZoomEnable(false).on('drawn.draw', setActiveElements);
56310             setActiveElements();
56311             surface.call(behavior);
56312             context.history().on('undone.draw', undone);
56313           };
56314
56315           drawWay.off = function (surface) {
56316             if (!_didResolveTempEdit) {
56317               // Drawing was interrupted unexpectedly.
56318               // This can happen if the user changes modes,
56319               // clicks geolocate button, a hashchange event occurs, etc.
56320               context.pauseChangeDispatch();
56321               resetToStartGraph();
56322               context.resumeChangeDispatch();
56323             }
56324
56325             _drawNode = undefined;
56326             _nodeIndex = undefined;
56327             context.map().on('drawn.draw', null);
56328             surface.call(behavior.off).selectAll('.active').classed('active', false);
56329             surface.classed('nope', false).classed('nope-suppressed', false).classed('nope-disabled', false);
56330             select(window).on('keydown.drawWay', null).on('keyup.drawWay', null);
56331             context.history().on('undone.draw', null);
56332           };
56333
56334           function attemptAdd(d, loc, doAdd) {
56335             if (_drawNode) {
56336               // move the node to the final loc in case move wasn't called
56337               // consistently (e.g. on touch devices)
56338               context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
56339               _drawNode = context.entity(_drawNode.id);
56340             } else {
56341               createDrawNode(loc);
56342             }
56343
56344             checkGeometry(true
56345             /* includeDrawNode */
56346             );
56347
56348             if (d && d.properties && d.properties.nope || context.surface().classed('nope')) {
56349               if (!_pointerHasMoved) {
56350                 // prevent the temporary draw node from appearing on touch devices
56351                 removeDrawNode();
56352               }
56353
56354               dispatch$1.call('rejectedSelfIntersection', this);
56355               return; // can't click here
56356             }
56357
56358             context.pauseChangeDispatch();
56359             doAdd(); // we just replaced the temporary edit with the real one
56360
56361             _didResolveTempEdit = true;
56362             context.resumeChangeDispatch();
56363             context.enter(mode);
56364           } // Accept the current position of the drawing node
56365
56366
56367           drawWay.add = function (loc, d) {
56368             attemptAdd(d, loc, function () {// don't need to do anything extra
56369             });
56370           }; // Connect the way to an existing way
56371
56372
56373           drawWay.addWay = function (loc, edge, d) {
56374             attemptAdd(d, loc, function () {
56375               context.replace(actionAddMidpoint({
56376                 loc: loc,
56377                 edge: edge
56378               }, _drawNode), _annotation);
56379             });
56380           }; // Connect the way to an existing node
56381
56382
56383           drawWay.addNode = function (node, d) {
56384             // finish drawing if the mapper targets the prior node
56385             if (node.id === _headNodeID || // or the first node when drawing an area
56386             _origWay.isClosed() && node.id === _origWay.first()) {
56387               drawWay.finish();
56388               return;
56389             }
56390
56391             attemptAdd(d, node.loc, function () {
56392               context.replace(function actionReplaceDrawNode(graph) {
56393                 // remove the temporary draw node and insert the existing node
56394                 // at the same index
56395                 graph = graph.replace(graph.entity(wayID).removeNode(_drawNode.id)).remove(_drawNode);
56396                 return graph.replace(graph.entity(wayID).addNode(node.id, _nodeIndex));
56397               }, _annotation);
56398             });
56399           }; // Finish the draw operation, removing the temporary edit.
56400           // If the way has enough nodes to be valid, it's selected.
56401           // Otherwise, delete everything and return to browse mode.
56402
56403
56404           drawWay.finish = function () {
56405             checkGeometry(false
56406             /* includeDrawNode */
56407             );
56408
56409             if (context.surface().classed('nope')) {
56410               dispatch$1.call('rejectedSelfIntersection', this);
56411               return; // can't click here
56412             }
56413
56414             context.pauseChangeDispatch(); // remove the temporary edit
56415
56416             context.pop(1);
56417             _didResolveTempEdit = true;
56418             context.resumeChangeDispatch();
56419             var way = context.hasEntity(wayID);
56420
56421             if (!way || way.isDegenerate()) {
56422               drawWay.cancel();
56423               return;
56424             }
56425
56426             window.setTimeout(function () {
56427               context.map().dblclickZoomEnable(true);
56428             }, 1000);
56429             var isNewFeature = !mode.isContinuing;
56430             context.enter(modeSelect(context, [wayID]).newFeature(isNewFeature));
56431           }; // Cancel the draw operation, delete everything, and return to browse mode.
56432
56433
56434           drawWay.cancel = function () {
56435             context.pauseChangeDispatch();
56436             resetToStartGraph();
56437             context.resumeChangeDispatch();
56438             window.setTimeout(function () {
56439               context.map().dblclickZoomEnable(true);
56440             }, 1000);
56441             context.surface().classed('nope', false).classed('nope-disabled', false).classed('nope-suppressed', false);
56442             context.enter(modeBrowse(context));
56443           };
56444
56445           drawWay.nodeIndex = function (val) {
56446             if (!arguments.length) return _nodeIndex;
56447             _nodeIndex = val;
56448             return drawWay;
56449           };
56450
56451           drawWay.activeID = function () {
56452             if (!arguments.length) return _drawNode && _drawNode.id; // no assign
56453
56454             return drawWay;
56455           };
56456
56457           return utilRebind(drawWay, dispatch$1, 'on');
56458         }
56459
56460         function modeDrawLine(context, wayID, startGraph, button, affix, continuing) {
56461           var mode = {
56462             button: button,
56463             id: 'draw-line'
56464           };
56465           var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on('rejectedSelfIntersection.modeDrawLine', function () {
56466             context.ui().flash.iconName('#iD-icon-no').label(_t('self_intersection.error.lines'))();
56467           });
56468           mode.wayID = wayID;
56469           mode.isContinuing = continuing;
56470
56471           mode.enter = function () {
56472             behavior.nodeIndex(affix === 'prefix' ? 0 : undefined);
56473             context.install(behavior);
56474           };
56475
56476           mode.exit = function () {
56477             context.uninstall(behavior);
56478           };
56479
56480           mode.selectedIDs = function () {
56481             return [wayID];
56482           };
56483
56484           mode.activeID = function () {
56485             return behavior && behavior.activeID() || [];
56486           };
56487
56488           return mode;
56489         }
56490
56491         function operationContinue(context, selectedIDs) {
56492           var _entities = selectedIDs.map(function (id) {
56493             return context.graph().entity(id);
56494           });
56495
56496           var _geometries = Object.assign({
56497             line: [],
56498             vertex: []
56499           }, utilArrayGroupBy(_entities, function (entity) {
56500             return entity.geometry(context.graph());
56501           }));
56502
56503           var _vertex = _geometries.vertex.length && _geometries.vertex[0];
56504
56505           function candidateWays() {
56506             return _vertex ? context.graph().parentWays(_vertex).filter(function (parent) {
56507               return parent.geometry(context.graph()) === 'line' && !parent.isClosed() && parent.affix(_vertex.id) && (_geometries.line.length === 0 || _geometries.line[0] === parent);
56508             }) : [];
56509           }
56510
56511           var _candidates = candidateWays();
56512
56513           var operation = function operation() {
56514             var candidate = _candidates[0];
56515             context.enter(modeDrawLine(context, candidate.id, context.graph(), 'line', candidate.affix(_vertex.id), true));
56516           };
56517
56518           operation.relatedEntityIds = function () {
56519             return _candidates.length ? [_candidates[0].id] : [];
56520           };
56521
56522           operation.available = function () {
56523             return _geometries.vertex.length === 1 && _geometries.line.length <= 1 && !context.features().hasHiddenConnections(_vertex, context.graph());
56524           };
56525
56526           operation.disabled = function () {
56527             if (_candidates.length === 0) {
56528               return 'not_eligible';
56529             } else if (_candidates.length > 1) {
56530               return 'multiple';
56531             }
56532
56533             return false;
56534           };
56535
56536           operation.tooltip = function () {
56537             var disable = operation.disabled();
56538             return disable ? _t('operations.continue.' + disable) : _t('operations.continue.description');
56539           };
56540
56541           operation.annotation = function () {
56542             return _t('operations.continue.annotation.line');
56543           };
56544
56545           operation.id = 'continue';
56546           operation.keys = [_t('operations.continue.key')];
56547           operation.title = _t('operations.continue.title');
56548           operation.behavior = behaviorOperation(context).which(operation);
56549           return operation;
56550         }
56551
56552         function operationCopy(context, selectedIDs) {
56553           function getFilteredIdsToCopy() {
56554             return selectedIDs.filter(function (selectedID) {
56555               var entity = context.graph().hasEntity(selectedID); // don't copy untagged vertices separately from ways
56556
56557               return entity.hasInterestingTags() || entity.geometry(context.graph()) !== 'vertex';
56558             });
56559           }
56560
56561           var operation = function operation() {
56562             var graph = context.graph();
56563             var selected = groupEntities(getFilteredIdsToCopy(), graph);
56564             var canCopy = [];
56565             var skip = {};
56566             var entity;
56567             var i;
56568
56569             for (i = 0; i < selected.relation.length; i++) {
56570               entity = selected.relation[i];
56571
56572               if (!skip[entity.id] && entity.isComplete(graph)) {
56573                 canCopy.push(entity.id);
56574                 skip = getDescendants(entity.id, graph, skip);
56575               }
56576             }
56577
56578             for (i = 0; i < selected.way.length; i++) {
56579               entity = selected.way[i];
56580
56581               if (!skip[entity.id]) {
56582                 canCopy.push(entity.id);
56583                 skip = getDescendants(entity.id, graph, skip);
56584               }
56585             }
56586
56587             for (i = 0; i < selected.node.length; i++) {
56588               entity = selected.node[i];
56589
56590               if (!skip[entity.id]) {
56591                 canCopy.push(entity.id);
56592               }
56593             }
56594
56595             context.copyIDs(canCopy);
56596
56597             if (_point && (canCopy.length !== 1 || graph.entity(canCopy[0]).type !== 'node')) {
56598               // store the anchor coordinates if copying more than a single node
56599               context.copyLonLat(context.projection.invert(_point));
56600             } else {
56601               context.copyLonLat(null);
56602             }
56603           };
56604
56605           function groupEntities(ids, graph) {
56606             var entities = ids.map(function (id) {
56607               return graph.entity(id);
56608             });
56609             return Object.assign({
56610               relation: [],
56611               way: [],
56612               node: []
56613             }, utilArrayGroupBy(entities, 'type'));
56614           }
56615
56616           function getDescendants(id, graph, descendants) {
56617             var entity = graph.entity(id);
56618             var children;
56619             descendants = descendants || {};
56620
56621             if (entity.type === 'relation') {
56622               children = entity.members.map(function (m) {
56623                 return m.id;
56624               });
56625             } else if (entity.type === 'way') {
56626               children = entity.nodes;
56627             } else {
56628               children = [];
56629             }
56630
56631             for (var i = 0; i < children.length; i++) {
56632               if (!descendants[children[i]]) {
56633                 descendants[children[i]] = true;
56634                 descendants = getDescendants(children[i], graph, descendants);
56635               }
56636             }
56637
56638             return descendants;
56639           }
56640
56641           operation.available = function () {
56642             return getFilteredIdsToCopy().length > 0;
56643           };
56644
56645           operation.disabled = function () {
56646             var extent = utilTotalExtent(getFilteredIdsToCopy(), context.graph());
56647
56648             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
56649               return 'too_large';
56650             }
56651
56652             return false;
56653           };
56654
56655           operation.availableForKeypress = function () {
56656             var selection = window.getSelection && window.getSelection(); // if the user has text selected then let them copy that, not the selected feature
56657
56658             return !selection || !selection.toString();
56659           };
56660
56661           operation.tooltip = function () {
56662             var disable = operation.disabled();
56663             return disable ? _t('operations.copy.' + disable, {
56664               n: selectedIDs.length
56665             }) : _t('operations.copy.description', {
56666               n: selectedIDs.length
56667             });
56668           };
56669
56670           operation.annotation = function () {
56671             return _t('operations.copy.annotation', {
56672               n: selectedIDs.length
56673             });
56674           };
56675
56676           var _point;
56677
56678           operation.point = function (val) {
56679             _point = val;
56680             return operation;
56681           };
56682
56683           operation.id = 'copy';
56684           operation.keys = [uiCmd('⌘C')];
56685           operation.title = _t('operations.copy.title');
56686           operation.behavior = behaviorOperation(context).which(operation);
56687           return operation;
56688         }
56689
56690         function operationDisconnect(context, selectedIDs) {
56691           var _vertexIDs = [];
56692           var _wayIDs = [];
56693           var _otherIDs = [];
56694           var _actions = [];
56695           selectedIDs.forEach(function (id) {
56696             var entity = context.entity(id);
56697
56698             if (entity.type === 'way') {
56699               _wayIDs.push(id);
56700             } else if (entity.geometry(context.graph()) === 'vertex') {
56701               _vertexIDs.push(id);
56702             } else {
56703               _otherIDs.push(id);
56704             }
56705           });
56706
56707           var _coords,
56708               _descriptionID = '',
56709               _annotationID = 'features';
56710
56711           var _disconnectingVertexIds = [];
56712           var _disconnectingWayIds = [];
56713
56714           if (_vertexIDs.length > 0) {
56715             // At the selected vertices, disconnect the selected ways, if any, else
56716             // disconnect all connected ways
56717             _disconnectingVertexIds = _vertexIDs;
56718
56719             _vertexIDs.forEach(function (vertexID) {
56720               var action = actionDisconnect(vertexID);
56721
56722               if (_wayIDs.length > 0) {
56723                 var waysIDsForVertex = _wayIDs.filter(function (wayID) {
56724                   var way = context.entity(wayID);
56725                   return way.nodes.indexOf(vertexID) !== -1;
56726                 });
56727
56728                 action.limitWays(waysIDsForVertex);
56729               }
56730
56731               _actions.push(action);
56732
56733               _disconnectingWayIds = _disconnectingWayIds.concat(context.graph().parentWays(context.graph().entity(vertexID)).map(function (d) {
56734                 return d.id;
56735               }));
56736             });
56737
56738             _disconnectingWayIds = utilArrayUniq(_disconnectingWayIds).filter(function (id) {
56739               return _wayIDs.indexOf(id) === -1;
56740             });
56741             _descriptionID += _actions.length === 1 ? 'single_point.' : 'multiple_points.';
56742
56743             if (_wayIDs.length === 1) {
56744               _descriptionID += 'single_way.' + context.graph().geometry(_wayIDs[0]);
56745             } else {
56746               _descriptionID += _wayIDs.length === 0 ? 'no_ways' : 'multiple_ways';
56747             }
56748           } else if (_wayIDs.length > 0) {
56749             // Disconnect the selected ways from each other, if they're connected,
56750             // else disconnect them from all connected ways
56751             var ways = _wayIDs.map(function (id) {
56752               return context.entity(id);
56753             });
56754
56755             var nodes = utilGetAllNodes(_wayIDs, context.graph());
56756             _coords = nodes.map(function (n) {
56757               return n.loc;
56758             }); // actions for connected nodes shared by at least two selected ways
56759
56760             var sharedActions = [];
56761             var sharedNodes = []; // actions for connected nodes
56762
56763             var unsharedActions = [];
56764             var unsharedNodes = [];
56765             nodes.forEach(function (node) {
56766               var action = actionDisconnect(node.id).limitWays(_wayIDs);
56767
56768               if (action.disabled(context.graph()) !== 'not_connected') {
56769                 var count = 0;
56770
56771                 for (var i in ways) {
56772                   var way = ways[i];
56773
56774                   if (way.nodes.indexOf(node.id) !== -1) {
56775                     count += 1;
56776                   }
56777
56778                   if (count > 1) break;
56779                 }
56780
56781                 if (count > 1) {
56782                   sharedActions.push(action);
56783                   sharedNodes.push(node);
56784                 } else {
56785                   unsharedActions.push(action);
56786                   unsharedNodes.push(node);
56787                 }
56788               }
56789             });
56790             _descriptionID += 'no_points.';
56791             _descriptionID += _wayIDs.length === 1 ? 'single_way.' : 'multiple_ways.';
56792
56793             if (sharedActions.length) {
56794               // if any nodes are shared, only disconnect the selected ways from each other
56795               _actions = sharedActions;
56796               _disconnectingVertexIds = sharedNodes.map(function (node) {
56797                 return node.id;
56798               });
56799               _descriptionID += 'conjoined';
56800               _annotationID = 'from_each_other';
56801             } else {
56802               // if no nodes are shared, disconnect the selected ways from all connected ways
56803               _actions = unsharedActions;
56804               _disconnectingVertexIds = unsharedNodes.map(function (node) {
56805                 return node.id;
56806               });
56807
56808               if (_wayIDs.length === 1) {
56809                 _descriptionID += context.graph().geometry(_wayIDs[0]);
56810               } else {
56811                 _descriptionID += 'separate';
56812               }
56813             }
56814           }
56815
56816           var _extent = utilTotalExtent(_disconnectingVertexIds, context.graph());
56817
56818           var operation = function operation() {
56819             context.perform(function (graph) {
56820               return _actions.reduce(function (graph, action) {
56821                 return action(graph);
56822               }, graph);
56823             }, operation.annotation());
56824             context.validator().validate();
56825           };
56826
56827           operation.relatedEntityIds = function () {
56828             if (_vertexIDs.length) {
56829               return _disconnectingWayIds;
56830             }
56831
56832             return _disconnectingVertexIds;
56833           };
56834
56835           operation.available = function () {
56836             if (_actions.length === 0) return false;
56837             if (_otherIDs.length !== 0) return false;
56838             if (_vertexIDs.length !== 0 && _wayIDs.length !== 0 && !_wayIDs.every(function (wayID) {
56839               return _vertexIDs.some(function (vertexID) {
56840                 var way = context.entity(wayID);
56841                 return way.nodes.indexOf(vertexID) !== -1;
56842               });
56843             })) return false;
56844             return true;
56845           };
56846
56847           operation.disabled = function () {
56848             var reason;
56849
56850             for (var actionIndex in _actions) {
56851               reason = _actions[actionIndex].disabled(context.graph());
56852               if (reason) return reason;
56853             }
56854
56855             if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
56856               return 'too_large.' + ((_vertexIDs.length ? _vertexIDs : _wayIDs).length === 1 ? 'single' : 'multiple');
56857             } else if (_coords && someMissing()) {
56858               return 'not_downloaded';
56859             } else if (selectedIDs.some(context.hasHiddenConnections)) {
56860               return 'connected_to_hidden';
56861             }
56862
56863             return false;
56864
56865             function someMissing() {
56866               if (context.inIntro()) return false;
56867               var osm = context.connection();
56868
56869               if (osm) {
56870                 var missing = _coords.filter(function (loc) {
56871                   return !osm.isDataLoaded(loc);
56872                 });
56873
56874                 if (missing.length) {
56875                   missing.forEach(function (loc) {
56876                     context.loadTileAtLoc(loc);
56877                   });
56878                   return true;
56879                 }
56880               }
56881
56882               return false;
56883             }
56884           };
56885
56886           operation.tooltip = function () {
56887             var disable = operation.disabled();
56888
56889             if (disable) {
56890               return _t('operations.disconnect.' + disable);
56891             }
56892
56893             return _t('operations.disconnect.description.' + _descriptionID);
56894           };
56895
56896           operation.annotation = function () {
56897             return _t('operations.disconnect.annotation.' + _annotationID);
56898           };
56899
56900           operation.id = 'disconnect';
56901           operation.keys = [_t('operations.disconnect.key')];
56902           operation.title = _t('operations.disconnect.title');
56903           operation.behavior = behaviorOperation(context).which(operation);
56904           return operation;
56905         }
56906
56907         function operationDowngrade(context, selectedIDs) {
56908           var _affectedFeatureCount = 0;
56909
56910           var _downgradeType = downgradeTypeForEntityIDs(selectedIDs);
56911
56912           var _multi = _affectedFeatureCount === 1 ? 'single' : 'multiple';
56913
56914           function downgradeTypeForEntityIDs(entityIds) {
56915             var downgradeType;
56916             _affectedFeatureCount = 0;
56917
56918             for (var i in entityIds) {
56919               var entityID = entityIds[i];
56920               var type = downgradeTypeForEntityID(entityID);
56921
56922               if (type) {
56923                 _affectedFeatureCount += 1;
56924
56925                 if (downgradeType && type !== downgradeType) {
56926                   if (downgradeType !== 'generic' && type !== 'generic') {
56927                     downgradeType = 'building_address';
56928                   } else {
56929                     downgradeType = 'generic';
56930                   }
56931                 } else {
56932                   downgradeType = type;
56933                 }
56934               }
56935             }
56936
56937             return downgradeType;
56938           }
56939
56940           function downgradeTypeForEntityID(entityID) {
56941             var graph = context.graph();
56942             var entity = graph.entity(entityID);
56943             var preset = _mainPresetIndex.match(entity, graph);
56944             if (!preset || preset.isFallback()) return null;
56945
56946             if (entity.type === 'node' && preset.id !== 'address' && Object.keys(entity.tags).some(function (key) {
56947               return key.match(/^addr:.{1,}/);
56948             })) {
56949               return 'address';
56950             }
56951
56952             var geometry = entity.geometry(graph);
56953
56954             if (geometry === 'area' && entity.tags.building && !preset.tags.building) {
56955               return 'building';
56956             }
56957
56958             if (geometry === 'vertex' && Object.keys(entity.tags).length) {
56959               return 'generic';
56960             }
56961
56962             return null;
56963           }
56964
56965           var buildingKeysToKeep = ['architect', 'building', 'height', 'layer', 'source', 'type', 'wheelchair'];
56966           var addressKeysToKeep = ['source'];
56967
56968           var operation = function operation() {
56969             context.perform(function (graph) {
56970               for (var i in selectedIDs) {
56971                 var entityID = selectedIDs[i];
56972                 var type = downgradeTypeForEntityID(entityID);
56973                 if (!type) continue;
56974                 var tags = Object.assign({}, graph.entity(entityID).tags); // shallow copy
56975
56976                 for (var key in tags) {
56977                   if (type === 'address' && addressKeysToKeep.indexOf(key) !== -1) continue;
56978
56979                   if (type === 'building') {
56980                     if (buildingKeysToKeep.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
56981                   }
56982
56983                   if (type !== 'generic') {
56984                     if (key.match(/^addr:.{1,}/) || key.match(/^source:.{1,}/)) continue;
56985                   }
56986
56987                   delete tags[key];
56988                 }
56989
56990                 graph = actionChangeTags(entityID, tags)(graph);
56991               }
56992
56993               return graph;
56994             }, operation.annotation());
56995             context.validator().validate(); // refresh the select mode to enable the delete operation
56996
56997             context.enter(modeSelect(context, selectedIDs));
56998           };
56999
57000           operation.available = function () {
57001             return _downgradeType;
57002           };
57003
57004           operation.disabled = function () {
57005             if (selectedIDs.some(hasWikidataTag)) {
57006               return 'has_wikidata_tag';
57007             }
57008
57009             return false;
57010
57011             function hasWikidataTag(id) {
57012               var entity = context.entity(id);
57013               return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
57014             }
57015           };
57016
57017           operation.tooltip = function () {
57018             var disable = operation.disabled();
57019             return disable ? _t('operations.downgrade.' + disable + '.' + _multi) : _t('operations.downgrade.description.' + _downgradeType);
57020           };
57021
57022           operation.annotation = function () {
57023             var suffix;
57024
57025             if (_downgradeType === 'building_address') {
57026               suffix = 'generic';
57027             } else {
57028               suffix = _downgradeType;
57029             }
57030
57031             return _t('operations.downgrade.annotation.' + suffix, {
57032               n: _affectedFeatureCount
57033             });
57034           };
57035
57036           operation.id = 'downgrade';
57037           operation.keys = [uiCmd('⌫')];
57038           operation.title = _t('operations.downgrade.title');
57039           operation.behavior = behaviorOperation(context).which(operation);
57040           return operation;
57041         }
57042
57043         function operationExtract(context, selectedIDs) {
57044           var _amount = selectedIDs.length === 1 ? 'single' : 'multiple';
57045
57046           var _geometries = utilArrayUniq(selectedIDs.map(function (entityID) {
57047             return context.graph().hasEntity(entityID) && context.graph().geometry(entityID);
57048           }).filter(Boolean));
57049
57050           var _geometryID = _geometries.length === 1 ? _geometries[0] : 'feature';
57051
57052           var _extent;
57053
57054           var _actions = selectedIDs.map(function (entityID) {
57055             var graph = context.graph();
57056             var entity = graph.hasEntity(entityID);
57057             if (!entity || !entity.hasInterestingTags()) return null;
57058             if (entity.type === 'node' && graph.parentWays(entity).length === 0) return null;
57059
57060             if (entity.type !== 'node') {
57061               var preset = _mainPresetIndex.match(entity, graph); // only allow extraction from ways/relations if the preset supports points
57062
57063               if (preset.geometry.indexOf('point') === -1) return null;
57064             }
57065
57066             _extent = _extent ? _extent.extend(entity.extent(graph)) : entity.extent(graph);
57067             return actionExtract(entityID);
57068           }).filter(Boolean);
57069
57070           var operation = function operation() {
57071             var combinedAction = function combinedAction(graph) {
57072               _actions.forEach(function (action) {
57073                 graph = action(graph);
57074               });
57075
57076               return graph;
57077             };
57078
57079             context.perform(combinedAction, operation.annotation()); // do the extract
57080
57081             var extractedNodeIDs = _actions.map(function (action) {
57082               return action.getExtractedNodeID();
57083             });
57084
57085             context.enter(modeSelect(context, extractedNodeIDs));
57086           };
57087
57088           operation.available = function () {
57089             return _actions.length && selectedIDs.length === _actions.length;
57090           };
57091
57092           operation.disabled = function () {
57093             if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
57094               return 'too_large';
57095             } else if (selectedIDs.some(function (entityID) {
57096               return context.graph().geometry(entityID) === 'vertex' && context.hasHiddenConnections(entityID);
57097             })) {
57098               return 'connected_to_hidden';
57099             }
57100
57101             return false;
57102           };
57103
57104           operation.tooltip = function () {
57105             var disableReason = operation.disabled();
57106
57107             if (disableReason) {
57108               return _t('operations.extract.' + disableReason + '.' + _amount);
57109             } else {
57110               return _t('operations.extract.description.' + _geometryID + '.' + _amount);
57111             }
57112           };
57113
57114           operation.annotation = function () {
57115             return _t('operations.extract.annotation', {
57116               n: selectedIDs.length
57117             });
57118           };
57119
57120           operation.id = 'extract';
57121           operation.keys = [_t('operations.extract.key')];
57122           operation.title = _t('operations.extract.title');
57123           operation.behavior = behaviorOperation(context).which(operation);
57124           return operation;
57125         }
57126
57127         function operationMerge(context, selectedIDs) {
57128           var _action = getAction();
57129
57130           function getAction() {
57131             // prefer a non-disabled action first
57132             var join = actionJoin(selectedIDs);
57133             if (!join.disabled(context.graph())) return join;
57134             var merge = actionMerge(selectedIDs);
57135             if (!merge.disabled(context.graph())) return merge;
57136             var mergePolygon = actionMergePolygon(selectedIDs);
57137             if (!mergePolygon.disabled(context.graph())) return mergePolygon;
57138             var mergeNodes = actionMergeNodes(selectedIDs);
57139             if (!mergeNodes.disabled(context.graph())) return mergeNodes; // otherwise prefer an action with an interesting disabled reason
57140
57141             if (join.disabled(context.graph()) !== 'not_eligible') return join;
57142             if (merge.disabled(context.graph()) !== 'not_eligible') return merge;
57143             if (mergePolygon.disabled(context.graph()) !== 'not_eligible') return mergePolygon;
57144             return mergeNodes;
57145           }
57146
57147           var operation = function operation() {
57148             if (operation.disabled()) return;
57149             context.perform(_action, operation.annotation());
57150             context.validator().validate();
57151             var resultIDs = selectedIDs.filter(context.hasEntity);
57152
57153             if (resultIDs.length > 1) {
57154               var interestingIDs = resultIDs.filter(function (id) {
57155                 return context.entity(id).hasInterestingTags();
57156               });
57157               if (interestingIDs.length) resultIDs = interestingIDs;
57158             }
57159
57160             context.enter(modeSelect(context, resultIDs));
57161           };
57162
57163           operation.available = function () {
57164             return selectedIDs.length >= 2;
57165           };
57166
57167           operation.disabled = function () {
57168             var actionDisabled = _action.disabled(context.graph());
57169
57170             if (actionDisabled) return actionDisabled;
57171             var osm = context.connection();
57172
57173             if (osm && _action.resultingWayNodesLength && _action.resultingWayNodesLength(context.graph()) > osm.maxWayNodes()) {
57174               return 'too_many_vertices';
57175             }
57176
57177             return false;
57178           };
57179
57180           operation.tooltip = function () {
57181             var disabled = operation.disabled();
57182
57183             if (disabled) {
57184               if (disabled === 'restriction') {
57185                 return _t('operations.merge.restriction', {
57186                   relation: _mainPresetIndex.item('type/restriction').name()
57187                 });
57188               }
57189
57190               return _t('operations.merge.' + disabled);
57191             }
57192
57193             return _t('operations.merge.description');
57194           };
57195
57196           operation.annotation = function () {
57197             return _t('operations.merge.annotation', {
57198               n: selectedIDs.length
57199             });
57200           };
57201
57202           operation.id = 'merge';
57203           operation.keys = [_t('operations.merge.key')];
57204           operation.title = _t('operations.merge.title');
57205           operation.behavior = behaviorOperation(context).which(operation);
57206           return operation;
57207         }
57208
57209         function operationPaste(context) {
57210           var _pastePoint;
57211
57212           var operation = function operation() {
57213             if (!_pastePoint) return;
57214             var oldIDs = context.copyIDs();
57215             if (!oldIDs.length) return;
57216             var projection = context.projection;
57217             var extent = geoExtent();
57218             var oldGraph = context.copyGraph();
57219             var newIDs = [];
57220             var action = actionCopyEntities(oldIDs, oldGraph);
57221             context.perform(action);
57222             var copies = action.copies();
57223             var originals = new Set();
57224             Object.values(copies).forEach(function (entity) {
57225               originals.add(entity.id);
57226             });
57227
57228             for (var id in copies) {
57229               var oldEntity = oldGraph.entity(id);
57230               var newEntity = copies[id];
57231
57232               extent._extend(oldEntity.extent(oldGraph)); // Exclude child nodes from newIDs if their parent way was also copied.
57233
57234
57235               var parents = context.graph().parentWays(newEntity);
57236               var parentCopied = parents.some(function (parent) {
57237                 return originals.has(parent.id);
57238               });
57239
57240               if (!parentCopied) {
57241                 newIDs.push(newEntity.id);
57242               }
57243             } // Use the location of the copy operation to offset the paste location,
57244             // or else use the center of the pasted extent
57245
57246
57247             var copyPoint = context.copyLonLat() && projection(context.copyLonLat()) || projection(extent.center());
57248             var delta = geoVecSubtract(_pastePoint, copyPoint); // Move the pasted objects to be anchored at the paste location
57249
57250             context.replace(actionMove(newIDs, delta, projection), operation.annotation());
57251             context.enter(modeSelect(context, newIDs));
57252           };
57253
57254           operation.point = function (val) {
57255             _pastePoint = val;
57256             return operation;
57257           };
57258
57259           operation.available = function () {
57260             return context.mode().id === 'browse';
57261           };
57262
57263           operation.disabled = function () {
57264             return !context.copyIDs().length;
57265           };
57266
57267           operation.tooltip = function () {
57268             var oldGraph = context.copyGraph();
57269             var ids = context.copyIDs();
57270
57271             if (!ids.length) {
57272               return _t('operations.paste.nothing_copied');
57273             }
57274
57275             return _t('operations.paste.description', {
57276               feature: utilDisplayLabel(oldGraph.entity(ids[0]), oldGraph),
57277               n: ids.length
57278             });
57279           };
57280
57281           operation.annotation = function () {
57282             var ids = context.copyIDs();
57283             return _t('operations.paste.annotation', {
57284               n: ids.length
57285             });
57286           };
57287
57288           operation.id = 'paste';
57289           operation.keys = [uiCmd('⌘V')];
57290           operation.title = _t('operations.paste.title');
57291           return operation;
57292         }
57293
57294         function operationReverse(context, selectedIDs) {
57295           var operation = function operation() {
57296             context.perform(function combinedReverseAction(graph) {
57297               actions().forEach(function (action) {
57298                 graph = action(graph);
57299               });
57300               return graph;
57301             }, operation.annotation());
57302             context.validator().validate();
57303           };
57304
57305           function actions(situation) {
57306             return selectedIDs.map(function (entityID) {
57307               var entity = context.hasEntity(entityID);
57308               if (!entity) return null;
57309
57310               if (situation === 'toolbar') {
57311                 if (entity.type === 'way' && !entity.isOneWay() && !entity.isSided()) return null;
57312               }
57313
57314               var geometry = entity.geometry(context.graph());
57315               if (entity.type !== 'node' && geometry !== 'line') return null;
57316               var action = actionReverse(entityID);
57317               if (action.disabled(context.graph())) return null;
57318               return action;
57319             }).filter(Boolean);
57320           }
57321
57322           function reverseTypeID() {
57323             var acts = actions();
57324             var nodeActionCount = acts.filter(function (act) {
57325               var entity = context.hasEntity(act.entityID());
57326               return entity && entity.type === 'node';
57327             }).length;
57328             if (nodeActionCount === 0) return 'line';
57329             if (nodeActionCount === acts.length) return 'point';
57330             return 'feature';
57331           }
57332
57333           operation.available = function (situation) {
57334             return actions(situation).length > 0;
57335           };
57336
57337           operation.disabled = function () {
57338             return false;
57339           };
57340
57341           operation.tooltip = function () {
57342             return _t('operations.reverse.description.' + reverseTypeID());
57343           };
57344
57345           operation.annotation = function () {
57346             var acts = actions();
57347             return _t('operations.reverse.annotation.' + reverseTypeID(), {
57348               n: acts.length
57349             });
57350           };
57351
57352           operation.id = 'reverse';
57353           operation.keys = [_t('operations.reverse.key')];
57354           operation.title = _t('operations.reverse.title');
57355           operation.behavior = behaviorOperation(context).which(operation);
57356           return operation;
57357         }
57358
57359         function operationSplit(context, selectedIDs) {
57360           var _vertexIds = selectedIDs.filter(function (id) {
57361             return context.graph().geometry(id) === 'vertex';
57362           });
57363
57364           var _selectedWayIds = selectedIDs.filter(function (id) {
57365             var entity = context.graph().hasEntity(id);
57366             return entity && entity.type === 'way';
57367           });
57368
57369           var _isAvailable = _vertexIds.length > 0 && _vertexIds.length + _selectedWayIds.length === selectedIDs.length;
57370
57371           var _action = actionSplit(_vertexIds);
57372
57373           var _ways = [];
57374           var _geometry = 'feature';
57375           var _waysAmount = 'single';
57376
57377           var _nodesAmount = _vertexIds.length === 1 ? 'single' : 'multiple';
57378
57379           if (_isAvailable) {
57380             if (_selectedWayIds.length) _action.limitWays(_selectedWayIds);
57381             _ways = _action.ways(context.graph());
57382             var geometries = {};
57383
57384             _ways.forEach(function (way) {
57385               geometries[way.geometry(context.graph())] = true;
57386             });
57387
57388             if (Object.keys(geometries).length === 1) {
57389               _geometry = Object.keys(geometries)[0];
57390             }
57391
57392             _waysAmount = _ways.length === 1 ? 'single' : 'multiple';
57393           }
57394
57395           var operation = function operation() {
57396             var difference = context.perform(_action, operation.annotation()); // select both the nodes and the ways so the mapper can immediately disconnect them if desired
57397
57398             var idsToSelect = _vertexIds.concat(difference.extantIDs().filter(function (id) {
57399               // filter out relations that may have had member additions
57400               return context.entity(id).type === 'way';
57401             }));
57402
57403             context.enter(modeSelect(context, idsToSelect));
57404           };
57405
57406           operation.relatedEntityIds = function () {
57407             return _selectedWayIds.length ? [] : _ways.map(function (way) {
57408               return way.id;
57409             });
57410           };
57411
57412           operation.available = function () {
57413             return _isAvailable;
57414           };
57415
57416           operation.disabled = function () {
57417             var reason = _action.disabled(context.graph());
57418
57419             if (reason) {
57420               return reason;
57421             } else if (selectedIDs.some(context.hasHiddenConnections)) {
57422               return 'connected_to_hidden';
57423             }
57424
57425             return false;
57426           };
57427
57428           operation.tooltip = function () {
57429             var disable = operation.disabled();
57430             if (disable) return _t('operations.split.' + disable);
57431             return _t('operations.split.description.' + _geometry + '.' + _waysAmount + '.' + _nodesAmount + '_node');
57432           };
57433
57434           operation.annotation = function () {
57435             return _t('operations.split.annotation.' + _geometry, {
57436               n: _ways.length
57437             });
57438           };
57439
57440           operation.id = 'split';
57441           operation.keys = [_t('operations.split.key')];
57442           operation.title = _t('operations.split.title');
57443           operation.behavior = behaviorOperation(context).which(operation);
57444           return operation;
57445         }
57446
57447         function operationStraighten(context, selectedIDs) {
57448           var _wayIDs = selectedIDs.filter(function (id) {
57449             return id.charAt(0) === 'w';
57450           });
57451
57452           var _nodeIDs = selectedIDs.filter(function (id) {
57453             return id.charAt(0) === 'n';
57454           });
57455
57456           var _amount = (_wayIDs.length ? _wayIDs : _nodeIDs).length === 1 ? 'single' : 'multiple';
57457
57458           var _nodes = utilGetAllNodes(selectedIDs, context.graph());
57459
57460           var _coords = _nodes.map(function (n) {
57461             return n.loc;
57462           });
57463
57464           var _extent = utilTotalExtent(selectedIDs, context.graph());
57465
57466           var _action = chooseAction();
57467
57468           var _geometry;
57469
57470           function chooseAction() {
57471             // straighten selected nodes
57472             if (_wayIDs.length === 0 && _nodeIDs.length > 2) {
57473               _geometry = 'point';
57474               return actionStraightenNodes(_nodeIDs, context.projection); // straighten selected ways (possibly between range of 2 selected nodes)
57475             } else if (_wayIDs.length > 0 && (_nodeIDs.length === 0 || _nodeIDs.length === 2)) {
57476               var startNodeIDs = [];
57477               var endNodeIDs = [];
57478
57479               for (var i = 0; i < selectedIDs.length; i++) {
57480                 var entity = context.entity(selectedIDs[i]);
57481
57482                 if (entity.type === 'node') {
57483                   continue;
57484                 } else if (entity.type !== 'way' || entity.isClosed()) {
57485                   return null; // exit early, can't straighten these
57486                 }
57487
57488                 startNodeIDs.push(entity.first());
57489                 endNodeIDs.push(entity.last());
57490               } // Remove duplicate end/startNodeIDs (duplicate nodes cannot be at the line end)
57491
57492
57493               startNodeIDs = startNodeIDs.filter(function (n) {
57494                 return startNodeIDs.indexOf(n) === startNodeIDs.lastIndexOf(n);
57495               });
57496               endNodeIDs = endNodeIDs.filter(function (n) {
57497                 return endNodeIDs.indexOf(n) === endNodeIDs.lastIndexOf(n);
57498               }); // Ensure all ways are connected (i.e. only 2 unique endpoints/startpoints)
57499
57500               if (utilArrayDifference(startNodeIDs, endNodeIDs).length + utilArrayDifference(endNodeIDs, startNodeIDs).length !== 2) return null; // Ensure path contains at least 3 unique nodes
57501
57502               var wayNodeIDs = utilGetAllNodes(_wayIDs, context.graph()).map(function (node) {
57503                 return node.id;
57504               });
57505               if (wayNodeIDs.length <= 2) return null; // If range of 2 selected nodes is supplied, ensure nodes lie on the selected path
57506
57507               if (_nodeIDs.length === 2 && (wayNodeIDs.indexOf(_nodeIDs[0]) === -1 || wayNodeIDs.indexOf(_nodeIDs[1]) === -1)) return null;
57508
57509               if (_nodeIDs.length) {
57510                 // If we're only straightenting between two points, we only need that extent visible
57511                 _extent = utilTotalExtent(_nodeIDs, context.graph());
57512               }
57513
57514               _geometry = 'line';
57515               return actionStraightenWay(selectedIDs, context.projection);
57516             }
57517
57518             return null;
57519           }
57520
57521           function operation() {
57522             if (!_action) return;
57523             context.perform(_action, operation.annotation());
57524             window.setTimeout(function () {
57525               context.validator().validate();
57526             }, 300); // after any transition
57527           }
57528
57529           operation.available = function () {
57530             return Boolean(_action);
57531           };
57532
57533           operation.disabled = function () {
57534             var reason = _action.disabled(context.graph());
57535
57536             if (reason) {
57537               return reason;
57538             } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
57539               return 'too_large';
57540             } else if (someMissing()) {
57541               return 'not_downloaded';
57542             } else if (selectedIDs.some(context.hasHiddenConnections)) {
57543               return 'connected_to_hidden';
57544             }
57545
57546             return false;
57547
57548             function someMissing() {
57549               if (context.inIntro()) return false;
57550               var osm = context.connection();
57551
57552               if (osm) {
57553                 var missing = _coords.filter(function (loc) {
57554                   return !osm.isDataLoaded(loc);
57555                 });
57556
57557                 if (missing.length) {
57558                   missing.forEach(function (loc) {
57559                     context.loadTileAtLoc(loc);
57560                   });
57561                   return true;
57562                 }
57563               }
57564
57565               return false;
57566             }
57567           };
57568
57569           operation.tooltip = function () {
57570             var disable = operation.disabled();
57571             return disable ? _t('operations.straighten.' + disable + '.' + _amount) : _t('operations.straighten.description.' + _geometry + (_wayIDs.length === 1 ? '' : 's'));
57572           };
57573
57574           operation.annotation = function () {
57575             return _t('operations.straighten.annotation.' + _geometry, {
57576               n: _wayIDs.length ? _wayIDs.length : _nodeIDs.length
57577             });
57578           };
57579
57580           operation.id = 'straighten';
57581           operation.keys = [_t('operations.straighten.key')];
57582           operation.title = _t('operations.straighten.title');
57583           operation.behavior = behaviorOperation(context).which(operation);
57584           return operation;
57585         }
57586
57587         var Operations = /*#__PURE__*/Object.freeze({
57588                 __proto__: null,
57589                 operationCircularize: operationCircularize,
57590                 operationContinue: operationContinue,
57591                 operationCopy: operationCopy,
57592                 operationDelete: operationDelete,
57593                 operationDisconnect: operationDisconnect,
57594                 operationDowngrade: operationDowngrade,
57595                 operationExtract: operationExtract,
57596                 operationMerge: operationMerge,
57597                 operationMove: operationMove,
57598                 operationOrthogonalize: operationOrthogonalize,
57599                 operationPaste: operationPaste,
57600                 operationReflectShort: operationReflectShort,
57601                 operationReflectLong: operationReflectLong,
57602                 operationReverse: operationReverse,
57603                 operationRotate: operationRotate,
57604                 operationSplit: operationSplit,
57605                 operationStraighten: operationStraighten
57606         });
57607
57608         var _relatedParent;
57609
57610         function modeSelect(context, selectedIDs) {
57611           var mode = {
57612             id: 'select',
57613             button: 'browse'
57614           };
57615           var keybinding = utilKeybinding('select');
57616
57617           var _breatheBehavior = behaviorBreathe();
57618
57619           var _modeDragNode = modeDragNode(context);
57620
57621           var _selectBehavior;
57622
57623           var _behaviors = [];
57624           var _operations = [];
57625           var _newFeature = false;
57626           var _follow = false;
57627
57628           function singular() {
57629             if (selectedIDs && selectedIDs.length === 1) {
57630               return context.hasEntity(selectedIDs[0]);
57631             }
57632           }
57633
57634           function selectedEntities() {
57635             return selectedIDs.map(function (id) {
57636               return context.hasEntity(id);
57637             }).filter(Boolean);
57638           }
57639
57640           function checkSelectedIDs() {
57641             var ids = [];
57642
57643             if (Array.isArray(selectedIDs)) {
57644               ids = selectedIDs.filter(function (id) {
57645                 return context.hasEntity(id);
57646               });
57647             }
57648
57649             if (!ids.length) {
57650               context.enter(modeBrowse(context));
57651               return false;
57652             } else if (selectedIDs.length > 1 && ids.length === 1 || selectedIDs.length === 1 && ids.length > 1) {
57653               // switch between single- and multi-select UI
57654               context.enter(modeSelect(context, ids));
57655               return false;
57656             }
57657
57658             selectedIDs = ids;
57659             return true;
57660           } // find the common parent ways for nextVertex, previousVertex
57661
57662
57663           function commonParents() {
57664             var graph = context.graph();
57665             var commonParents = [];
57666
57667             for (var i = 0; i < selectedIDs.length; i++) {
57668               var entity = context.hasEntity(selectedIDs[i]);
57669
57670               if (!entity || entity.geometry(graph) !== 'vertex') {
57671                 return []; // selection includes some not vertices
57672               }
57673
57674               var currParents = graph.parentWays(entity).map(function (w) {
57675                 return w.id;
57676               });
57677
57678               if (!commonParents.length) {
57679                 commonParents = currParents;
57680                 continue;
57681               }
57682
57683               commonParents = utilArrayIntersection(commonParents, currParents);
57684
57685               if (!commonParents.length) {
57686                 return [];
57687               }
57688             }
57689
57690             return commonParents;
57691           }
57692
57693           function singularParent() {
57694             var parents = commonParents();
57695
57696             if (!parents || parents.length === 0) {
57697               _relatedParent = null;
57698               return null;
57699             } // relatedParent is used when we visit a vertex with multiple
57700             // parents, and we want to remember which parent line we started on.
57701
57702
57703             if (parents.length === 1) {
57704               _relatedParent = parents[0]; // remember this parent for later
57705
57706               return _relatedParent;
57707             }
57708
57709             if (parents.indexOf(_relatedParent) !== -1) {
57710               return _relatedParent; // prefer the previously seen parent
57711             }
57712
57713             return parents[0];
57714           }
57715
57716           mode.selectedIDs = function (val) {
57717             if (!arguments.length) return selectedIDs;
57718             selectedIDs = val;
57719             return mode;
57720           };
57721
57722           mode.zoomToSelected = function () {
57723             context.map().zoomToEase(selectedEntities());
57724           };
57725
57726           mode.newFeature = function (val) {
57727             if (!arguments.length) return _newFeature;
57728             _newFeature = val;
57729             return mode;
57730           };
57731
57732           mode.selectBehavior = function (val) {
57733             if (!arguments.length) return _selectBehavior;
57734             _selectBehavior = val;
57735             return mode;
57736           };
57737
57738           mode.follow = function (val) {
57739             if (!arguments.length) return _follow;
57740             _follow = val;
57741             return mode;
57742           };
57743
57744           function loadOperations() {
57745             _operations.forEach(function (operation) {
57746               if (operation.behavior) {
57747                 context.uninstall(operation.behavior);
57748               }
57749             });
57750
57751             _operations = Object.values(Operations).map(function (o) {
57752               return o(context, selectedIDs);
57753             }).filter(function (o) {
57754               return o.id !== 'delete' && o.id !== 'downgrade' && o.id !== 'copy';
57755             }).concat([// group copy/downgrade/delete operation together at the end of the list
57756             operationCopy(context, selectedIDs), operationDowngrade(context, selectedIDs), operationDelete(context, selectedIDs)]).filter(function (operation) {
57757               return operation.available();
57758             });
57759
57760             _operations.forEach(function (operation) {
57761               if (operation.behavior) {
57762                 context.install(operation.behavior);
57763               }
57764             }); // remove any displayed menu
57765
57766
57767             context.ui().closeEditMenu();
57768           }
57769
57770           mode.operations = function () {
57771             return _operations;
57772           };
57773
57774           mode.enter = function () {
57775             if (!checkSelectedIDs()) return;
57776             context.features().forceVisible(selectedIDs);
57777
57778             _modeDragNode.restoreSelectedIDs(selectedIDs);
57779
57780             loadOperations();
57781
57782             if (!_behaviors.length) {
57783               if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
57784               _behaviors = [behaviorPaste(context), _breatheBehavior, behaviorHover(context).on('hover', context.ui().sidebar.hoverModeSelect), _selectBehavior, behaviorLasso(context), _modeDragNode.behavior, modeDragNote(context).behavior];
57785             }
57786
57787             _behaviors.forEach(context.install);
57788
57789             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) {
57790               return uiCmd('⇧' + key);
57791             }), scaleSelection(1.05)).on(utilKeybinding.plusKeys.map(function (key) {
57792               return uiCmd('⇧⌥' + key);
57793             }), scaleSelection(Math.pow(1.05, 5))).on(utilKeybinding.minusKeys.map(function (key) {
57794               return uiCmd('⇧' + key);
57795             }), scaleSelection(1 / 1.05)).on(utilKeybinding.minusKeys.map(function (key) {
57796               return uiCmd('⇧⌥' + key);
57797             }), scaleSelection(1 / Math.pow(1.05, 5))).on(['\\', 'pause'], nextParent).on('⎋', esc, true);
57798             select(document).call(keybinding);
57799             context.ui().sidebar.select(selectedIDs, _newFeature);
57800             context.history().on('change.select', function () {
57801               loadOperations(); // reselect after change in case relation members were removed or added
57802
57803               selectElements();
57804             }).on('undone.select', checkSelectedIDs).on('redone.select', checkSelectedIDs);
57805             context.map().on('drawn.select', selectElements).on('crossEditableZoom.select', function () {
57806               selectElements();
57807
57808               _breatheBehavior.restartIfNeeded(context.surface());
57809             });
57810             context.map().doubleUpHandler().on('doubleUp.modeSelect', didDoubleUp);
57811             selectElements();
57812
57813             if (_follow) {
57814               var extent = geoExtent();
57815               var graph = context.graph();
57816               selectedIDs.forEach(function (id) {
57817                 var entity = context.entity(id);
57818
57819                 extent._extend(entity.extent(graph));
57820               });
57821               var loc = extent.center();
57822               context.map().centerEase(loc); // we could enter the mode multiple times, so reset follow for next time
57823
57824               _follow = false;
57825             }
57826
57827             function nudgeSelection(delta) {
57828               return function () {
57829                 // prevent nudging during low zoom selection
57830                 if (!context.map().withinEditableZoom()) return;
57831                 var moveOp = operationMove(context, selectedIDs);
57832
57833                 if (moveOp.disabled()) {
57834                   context.ui().flash.duration(4000).iconName('#iD-operation-' + moveOp.id).iconClass('operation disabled').label(moveOp.tooltip)();
57835                 } else {
57836                   context.perform(actionMove(selectedIDs, delta, context.projection), moveOp.annotation());
57837                   context.validator().validate();
57838                 }
57839               };
57840             }
57841
57842             function scaleSelection(factor) {
57843               return function () {
57844                 // prevent scaling during low zoom selection
57845                 if (!context.map().withinEditableZoom()) return;
57846                 var nodes = utilGetAllNodes(selectedIDs, context.graph());
57847                 var isUp = factor > 1; // can only scale if multiple nodes are selected
57848
57849                 if (nodes.length <= 1) return;
57850                 var extent = utilTotalExtent(selectedIDs, context.graph()); // These disabled checks would normally be handled by an operation
57851                 // object, but we don't want an actual scale operation at this point.
57852
57853                 function scalingDisabled() {
57854                   if (tooSmall()) {
57855                     return 'too_small';
57856                   } else if (extent.percentContainedIn(context.map().extent()) < 0.8) {
57857                     return 'too_large';
57858                   } else if (someMissing() || selectedIDs.some(incompleteRelation)) {
57859                     return 'not_downloaded';
57860                   } else if (selectedIDs.some(context.hasHiddenConnections)) {
57861                     return 'connected_to_hidden';
57862                   }
57863
57864                   return false;
57865
57866                   function tooSmall() {
57867                     if (isUp) return false;
57868                     var dLon = Math.abs(extent[1][0] - extent[0][0]);
57869                     var dLat = Math.abs(extent[1][1] - extent[0][1]);
57870                     return dLon < geoMetersToLon(1, extent[1][1]) && dLat < geoMetersToLat(1);
57871                   }
57872
57873                   function someMissing() {
57874                     if (context.inIntro()) return false;
57875                     var osm = context.connection();
57876
57877                     if (osm) {
57878                       var missing = nodes.filter(function (n) {
57879                         return !osm.isDataLoaded(n.loc);
57880                       });
57881
57882                       if (missing.length) {
57883                         missing.forEach(function (loc) {
57884                           context.loadTileAtLoc(loc);
57885                         });
57886                         return true;
57887                       }
57888                     }
57889
57890                     return false;
57891                   }
57892
57893                   function incompleteRelation(id) {
57894                     var entity = context.entity(id);
57895                     return entity.type === 'relation' && !entity.isComplete(context.graph());
57896                   }
57897                 }
57898
57899                 var disabled = scalingDisabled();
57900
57901                 if (disabled) {
57902                   var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
57903                   context.ui().flash.duration(4000).iconName('#iD-icon-no').iconClass('operation disabled').label(_t('operations.scale.' + disabled + '.' + multi))();
57904                 } else {
57905                   var pivot = context.projection(extent.center());
57906                   var annotation = _t('operations.scale.annotation.' + (isUp ? 'up' : 'down') + '.feature', {
57907                     n: selectedIDs.length
57908                   });
57909                   context.perform(actionScale(selectedIDs, pivot, factor, context.projection), annotation);
57910                   context.validator().validate();
57911                 }
57912               };
57913             }
57914
57915             function didDoubleUp(d3_event, loc) {
57916               if (!context.map().withinEditableZoom()) return;
57917               var target = select(d3_event.target);
57918               var datum = target.datum();
57919               var entity = datum && datum.properties && datum.properties.entity;
57920               if (!entity) return;
57921
57922               if (entity instanceof osmWay && target.classed('target')) {
57923                 var choice = geoChooseEdge(context.graph().childNodes(entity), loc, context.projection);
57924                 var prev = entity.nodes[choice.index - 1];
57925                 var next = entity.nodes[choice.index];
57926                 context.perform(actionAddMidpoint({
57927                   loc: choice.loc,
57928                   edge: [prev, next]
57929                 }, osmNode()), _t('operations.add.annotation.vertex'));
57930               } else if (entity.type === 'midpoint') {
57931                 context.perform(actionAddMidpoint({
57932                   loc: entity.loc,
57933                   edge: entity.edge
57934                 }, osmNode()), _t('operations.add.annotation.vertex'));
57935               }
57936             }
57937
57938             function selectElements() {
57939               if (!checkSelectedIDs()) return;
57940               var surface = context.surface();
57941               surface.selectAll('.selected-member').classed('selected-member', false);
57942               surface.selectAll('.selected').classed('selected', false);
57943               surface.selectAll('.related').classed('related', false);
57944               singularParent();
57945
57946               if (_relatedParent) {
57947                 surface.selectAll(utilEntitySelector([_relatedParent])).classed('related', true);
57948               }
57949
57950               if (context.map().withinEditableZoom()) {
57951                 // Apply selection styling if not in wide selection
57952                 surface.selectAll(utilDeepMemberSelector(selectedIDs, context.graph(), true
57953                 /* skipMultipolgonMembers */
57954                 )).classed('selected-member', true);
57955                 surface.selectAll(utilEntityOrDeepMemberSelector(selectedIDs, context.graph())).classed('selected', true);
57956               }
57957             }
57958
57959             function esc() {
57960               if (context.container().select('.combobox').size()) return;
57961               context.enter(modeBrowse(context));
57962             }
57963
57964             function firstVertex(d3_event) {
57965               d3_event.preventDefault();
57966               var entity = singular();
57967               var parent = singularParent();
57968               var way;
57969
57970               if (entity && entity.type === 'way') {
57971                 way = entity;
57972               } else if (parent) {
57973                 way = context.entity(parent);
57974               }
57975
57976               if (way) {
57977                 context.enter(modeSelect(context, [way.first()]).follow(true));
57978               }
57979             }
57980
57981             function lastVertex(d3_event) {
57982               d3_event.preventDefault();
57983               var entity = singular();
57984               var parent = singularParent();
57985               var way;
57986
57987               if (entity && entity.type === 'way') {
57988                 way = entity;
57989               } else if (parent) {
57990                 way = context.entity(parent);
57991               }
57992
57993               if (way) {
57994                 context.enter(modeSelect(context, [way.last()]).follow(true));
57995               }
57996             }
57997
57998             function previousVertex(d3_event) {
57999               d3_event.preventDefault();
58000               var parent = singularParent();
58001               if (!parent) return;
58002               var way = context.entity(parent);
58003               var length = way.nodes.length;
58004               var curr = way.nodes.indexOf(selectedIDs[0]);
58005               var index = -1;
58006
58007               if (curr > 0) {
58008                 index = curr - 1;
58009               } else if (way.isClosed()) {
58010                 index = length - 2;
58011               }
58012
58013               if (index !== -1) {
58014                 context.enter(modeSelect(context, [way.nodes[index]]).follow(true));
58015               }
58016             }
58017
58018             function nextVertex(d3_event) {
58019               d3_event.preventDefault();
58020               var parent = singularParent();
58021               if (!parent) return;
58022               var way = context.entity(parent);
58023               var length = way.nodes.length;
58024               var curr = way.nodes.indexOf(selectedIDs[0]);
58025               var index = -1;
58026
58027               if (curr < length - 1) {
58028                 index = curr + 1;
58029               } else if (way.isClosed()) {
58030                 index = 0;
58031               }
58032
58033               if (index !== -1) {
58034                 context.enter(modeSelect(context, [way.nodes[index]]).follow(true));
58035               }
58036             }
58037
58038             function nextParent(d3_event) {
58039               d3_event.preventDefault();
58040               var parents = commonParents();
58041               if (!parents || parents.length < 2) return;
58042               var index = parents.indexOf(_relatedParent);
58043
58044               if (index < 0 || index > parents.length - 2) {
58045                 _relatedParent = parents[0];
58046               } else {
58047                 _relatedParent = parents[index + 1];
58048               }
58049
58050               var surface = context.surface();
58051               surface.selectAll('.related').classed('related', false);
58052
58053               if (_relatedParent) {
58054                 surface.selectAll(utilEntitySelector([_relatedParent])).classed('related', true);
58055               }
58056             }
58057           };
58058
58059           mode.exit = function () {
58060             _newFeature = false;
58061
58062             _operations.forEach(function (operation) {
58063               if (operation.behavior) {
58064                 context.uninstall(operation.behavior);
58065               }
58066             });
58067
58068             _operations = [];
58069
58070             _behaviors.forEach(context.uninstall);
58071
58072             select(document).call(keybinding.unbind);
58073             context.ui().closeEditMenu();
58074             context.history().on('change.select', null).on('undone.select', null).on('redone.select', null);
58075             var surface = context.surface();
58076             surface.selectAll('.selected-member').classed('selected-member', false);
58077             surface.selectAll('.selected').classed('selected', false);
58078             surface.selectAll('.highlighted').classed('highlighted', false);
58079             surface.selectAll('.related').classed('related', false);
58080             context.map().on('drawn.select', null);
58081             context.ui().sidebar.hide();
58082             context.features().forceVisible([]);
58083             var entity = singular();
58084
58085             if (_newFeature && entity && entity.type === 'relation' && // no tags
58086             Object.keys(entity.tags).length === 0 && // no parent relations
58087             context.graph().parentRelations(entity).length === 0 && ( // no members or one member with no role
58088             entity.members.length === 0 || entity.members.length === 1 && !entity.members[0].role)) {
58089               // the user added this relation but didn't edit it at all, so just delete it
58090               var deleteAction = actionDeleteRelation(entity.id, true
58091               /* don't delete untagged members */
58092               );
58093               context.perform(deleteAction, _t('operations.delete.annotation.relation'));
58094             }
58095           };
58096
58097           return mode;
58098         }
58099
58100         function uiLasso(context) {
58101           var group, polygon;
58102           lasso.coordinates = [];
58103
58104           function lasso(selection) {
58105             context.container().classed('lasso', true);
58106             group = selection.append('g').attr('class', 'lasso hide');
58107             polygon = group.append('path').attr('class', 'lasso-path');
58108             group.call(uiToggle(true));
58109           }
58110
58111           function draw() {
58112             if (polygon) {
58113               polygon.data([lasso.coordinates]).attr('d', function (d) {
58114                 return 'M' + d.join(' L') + ' Z';
58115               });
58116             }
58117           }
58118
58119           lasso.extent = function () {
58120             return lasso.coordinates.reduce(function (extent, point) {
58121               return extent.extend(geoExtent(point));
58122             }, geoExtent());
58123           };
58124
58125           lasso.p = function (_) {
58126             if (!arguments.length) return lasso;
58127             lasso.coordinates.push(_);
58128             draw();
58129             return lasso;
58130           };
58131
58132           lasso.close = function () {
58133             if (group) {
58134               group.call(uiToggle(false, function () {
58135                 select(this).remove();
58136               }));
58137             }
58138
58139             context.container().classed('lasso', false);
58140           };
58141
58142           return lasso;
58143         }
58144
58145         function behaviorLasso(context) {
58146           // use pointer events on supported platforms; fallback to mouse events
58147           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
58148
58149           var behavior = function behavior(selection) {
58150             var lasso;
58151
58152             function pointerdown(d3_event) {
58153               var button = 0; // left
58154
58155               if (d3_event.button === button && d3_event.shiftKey === true) {
58156                 lasso = null;
58157                 select(window).on(_pointerPrefix + 'move.lasso', pointermove).on(_pointerPrefix + 'up.lasso', pointerup);
58158                 d3_event.stopPropagation();
58159               }
58160             }
58161
58162             function pointermove() {
58163               if (!lasso) {
58164                 lasso = uiLasso(context);
58165                 context.surface().call(lasso);
58166               }
58167
58168               lasso.p(context.map().mouse());
58169             }
58170
58171             function normalize(a, b) {
58172               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])]];
58173             }
58174
58175             function lassoed() {
58176               if (!lasso) return [];
58177               var graph = context.graph();
58178               var limitToNodes;
58179
58180               if (context.map().editableDataEnabled(true
58181               /* skipZoomCheck */
58182               ) && context.map().isInWideSelection()) {
58183                 // only select from the visible nodes
58184                 limitToNodes = new Set(utilGetAllNodes(context.selectedIDs(), graph));
58185               } else if (!context.map().editableDataEnabled()) {
58186                 return [];
58187               }
58188
58189               var bounds = lasso.extent().map(context.projection.invert);
58190               var extent = geoExtent(normalize(bounds[0], bounds[1]));
58191               var intersects = context.history().intersects(extent).filter(function (entity) {
58192                 return entity.type === 'node' && (!limitToNodes || limitToNodes.has(entity)) && geoPointInPolygon(context.projection(entity.loc), lasso.coordinates) && !context.features().isHidden(entity, graph, entity.geometry(graph));
58193               }); // sort the lassoed nodes as best we can
58194
58195               intersects.sort(function (node1, node2) {
58196                 var parents1 = graph.parentWays(node1);
58197                 var parents2 = graph.parentWays(node2);
58198
58199                 if (parents1.length && parents2.length) {
58200                   // both nodes are vertices
58201                   var sharedParents = utilArrayIntersection(parents1, parents2);
58202
58203                   if (sharedParents.length) {
58204                     var sharedParentNodes = sharedParents[0].nodes; // vertices are members of the same way; sort them in their listed order
58205
58206                     return sharedParentNodes.indexOf(node1.id) - sharedParentNodes.indexOf(node2.id);
58207                   } else {
58208                     // vertices do not share a way; group them by their respective parent ways
58209                     return parseFloat(parents1[0].id.slice(1)) - parseFloat(parents2[0].id.slice(1));
58210                   }
58211                 } else if (parents1.length || parents2.length) {
58212                   // only one node is a vertex; sort standalone points before vertices
58213                   return parents1.length - parents2.length;
58214                 } // both nodes are standalone points; sort left to right
58215
58216
58217                 return node1.loc[0] - node2.loc[0];
58218               });
58219               return intersects.map(function (entity) {
58220                 return entity.id;
58221               });
58222             }
58223
58224             function pointerup() {
58225               select(window).on(_pointerPrefix + 'move.lasso', null).on(_pointerPrefix + 'up.lasso', null);
58226               if (!lasso) return;
58227               var ids = lassoed();
58228               lasso.close();
58229
58230               if (ids.length) {
58231                 context.enter(modeSelect(context, ids));
58232               }
58233             }
58234
58235             selection.on(_pointerPrefix + 'down.lasso', pointerdown);
58236           };
58237
58238           behavior.off = function (selection) {
58239             selection.on(_pointerPrefix + 'down.lasso', null);
58240           };
58241
58242           return behavior;
58243         }
58244
58245         function modeBrowse(context) {
58246           var mode = {
58247             button: 'browse',
58248             id: 'browse',
58249             title: _t('modes.browse.title'),
58250             description: _t('modes.browse.description')
58251           };
58252           var sidebar;
58253
58254           var _selectBehavior;
58255
58256           var _behaviors = [];
58257
58258           mode.selectBehavior = function (val) {
58259             if (!arguments.length) return _selectBehavior;
58260             _selectBehavior = val;
58261             return mode;
58262           };
58263
58264           mode.enter = function () {
58265             if (!_behaviors.length) {
58266               if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
58267               _behaviors = [behaviorPaste(context), behaviorHover(context).on('hover', context.ui().sidebar.hover), _selectBehavior, behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
58268             }
58269
58270             _behaviors.forEach(context.install); // Get focus on the body.
58271
58272
58273             if (document.activeElement && document.activeElement.blur) {
58274               document.activeElement.blur();
58275             }
58276
58277             if (sidebar) {
58278               context.ui().sidebar.show(sidebar);
58279             } else {
58280               context.ui().sidebar.select(null);
58281             }
58282           };
58283
58284           mode.exit = function () {
58285             context.ui().sidebar.hover.cancel();
58286
58287             _behaviors.forEach(context.uninstall);
58288
58289             if (sidebar) {
58290               context.ui().sidebar.hide();
58291             }
58292           };
58293
58294           mode.sidebar = function (_) {
58295             if (!arguments.length) return sidebar;
58296             sidebar = _;
58297             return mode;
58298           };
58299
58300           mode.operations = function () {
58301             return [operationPaste(context)];
58302           };
58303
58304           return mode;
58305         }
58306
58307         function behaviorAddWay(context) {
58308           var dispatch$1 = dispatch('start', 'startFromWay', 'startFromNode');
58309           var draw = behaviorDraw(context);
58310
58311           function behavior(surface) {
58312             draw.on('click', function () {
58313               dispatch$1.apply('start', this, arguments);
58314             }).on('clickWay', function () {
58315               dispatch$1.apply('startFromWay', this, arguments);
58316             }).on('clickNode', function () {
58317               dispatch$1.apply('startFromNode', this, arguments);
58318             }).on('cancel', behavior.cancel).on('finish', behavior.cancel);
58319             context.map().dblclickZoomEnable(false);
58320             surface.call(draw);
58321           }
58322
58323           behavior.off = function (surface) {
58324             surface.call(draw.off);
58325           };
58326
58327           behavior.cancel = function () {
58328             window.setTimeout(function () {
58329               context.map().dblclickZoomEnable(true);
58330             }, 1000);
58331             context.enter(modeBrowse(context));
58332           };
58333
58334           return utilRebind(behavior, dispatch$1, 'on');
58335         }
58336
58337         function behaviorHash(context) {
58338           // cached window.location.hash
58339           var _cachedHash = null; // allowable latitude range
58340
58341           var _latitudeLimit = 90 - 1e-8;
58342
58343           function computedHashParameters() {
58344             var map = context.map();
58345             var center = map.center();
58346             var zoom = map.zoom();
58347             var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
58348             var oldParams = utilObjectOmit(utilStringQs(window.location.hash), ['comment', 'source', 'hashtags', 'walkthrough']);
58349             var newParams = {};
58350             delete oldParams.id;
58351             var selected = context.selectedIDs().filter(function (id) {
58352               return context.hasEntity(id);
58353             });
58354
58355             if (selected.length) {
58356               newParams.id = selected.join(',');
58357             }
58358
58359             newParams.map = zoom.toFixed(2) + '/' + center[1].toFixed(precision) + '/' + center[0].toFixed(precision);
58360             return Object.assign(oldParams, newParams);
58361           }
58362
58363           function computedHash() {
58364             return '#' + utilQsString(computedHashParameters(), true);
58365           }
58366
58367           function computedTitle(includeChangeCount) {
58368             var baseTitle = context.documentTitleBase() || 'iD';
58369             var contextual;
58370             var changeCount;
58371             var titleID;
58372             var selected = context.selectedIDs().filter(function (id) {
58373               return context.hasEntity(id);
58374             });
58375
58376             if (selected.length) {
58377               var firstLabel = utilDisplayLabel(context.entity(selected[0]), context.graph());
58378
58379               if (selected.length > 1) {
58380                 contextual = _t('title.labeled_and_more', {
58381                   labeled: firstLabel,
58382                   count: selected.length - 1
58383                 });
58384               } else {
58385                 contextual = firstLabel;
58386               }
58387
58388               titleID = 'context';
58389             }
58390
58391             if (includeChangeCount) {
58392               changeCount = context.history().difference().summary().length;
58393
58394               if (changeCount > 0) {
58395                 titleID = contextual ? 'changes_context' : 'changes';
58396               }
58397             }
58398
58399             if (titleID) {
58400               return _t('title.format.' + titleID, {
58401                 changes: changeCount,
58402                 base: baseTitle,
58403                 context: contextual
58404               });
58405             }
58406
58407             return baseTitle;
58408           }
58409
58410           function updateTitle(includeChangeCount) {
58411             if (!context.setsDocumentTitle()) return;
58412             var newTitle = computedTitle(includeChangeCount);
58413
58414             if (document.title !== newTitle) {
58415               document.title = newTitle;
58416             }
58417           }
58418
58419           function updateHashIfNeeded() {
58420             if (context.inIntro()) return;
58421             var latestHash = computedHash();
58422
58423             if (_cachedHash !== latestHash) {
58424               _cachedHash = latestHash; // Update the URL hash without affecting the browser navigation stack,
58425               // though unavoidably creating a browser history entry
58426
58427               window.history.replaceState(null, computedTitle(false
58428               /* includeChangeCount */
58429               ), latestHash); // set the title we want displayed for the browser tab/window
58430
58431               updateTitle(true
58432               /* includeChangeCount */
58433               );
58434             }
58435           }
58436
58437           var _throttledUpdate = throttle(updateHashIfNeeded, 500);
58438
58439           var _throttledUpdateTitle = throttle(function () {
58440             updateTitle(true
58441             /* includeChangeCount */
58442             );
58443           }, 500);
58444
58445           function hashchange() {
58446             // ignore spurious hashchange events
58447             if (window.location.hash === _cachedHash) return;
58448             _cachedHash = window.location.hash;
58449             var q = utilStringQs(_cachedHash);
58450             var mapArgs = (q.map || '').split('/').map(Number);
58451
58452             if (mapArgs.length < 3 || mapArgs.some(isNaN)) {
58453               // replace bogus hash
58454               updateHashIfNeeded();
58455             } else {
58456               // don't update if the new hash already reflects the state of iD
58457               if (_cachedHash === computedHash()) return;
58458               var mode = context.mode();
58459               context.map().centerZoom([mapArgs[2], Math.min(_latitudeLimit, Math.max(-_latitudeLimit, mapArgs[1]))], mapArgs[0]);
58460
58461               if (q.id && mode) {
58462                 var ids = q.id.split(',').filter(function (id) {
58463                   return context.hasEntity(id);
58464                 });
58465
58466                 if (ids.length && (mode.id === 'browse' || mode.id === 'select' && !utilArrayIdentical(mode.selectedIDs(), ids))) {
58467                   context.enter(modeSelect(context, ids));
58468                   return;
58469                 }
58470               }
58471
58472               var center = context.map().center();
58473               var dist = geoSphericalDistance(center, [mapArgs[2], mapArgs[1]]);
58474               var maxdist = 500; // Don't allow the hash location to change too much while drawing
58475               // This can happen if the user accidentally hit the back button.  #3996
58476
58477               if (mode && mode.id.match(/^draw/) !== null && dist > maxdist) {
58478                 context.enter(modeBrowse(context));
58479                 return;
58480               }
58481             }
58482           }
58483
58484           function behavior() {
58485             context.map().on('move.behaviorHash', _throttledUpdate);
58486             context.history().on('change.behaviorHash', _throttledUpdateTitle);
58487             context.on('enter.behaviorHash', _throttledUpdate);
58488             select(window).on('hashchange.behaviorHash', hashchange);
58489
58490             if (window.location.hash) {
58491               var q = utilStringQs(window.location.hash);
58492
58493               if (q.id) {
58494                 //if (!context.history().hasRestorableChanges()) {
58495                 // targeting specific features: download, select, and zoom to them
58496                 context.zoomToEntity(q.id.split(',')[0], !q.map); //}
58497               }
58498
58499               if (q.walkthrough === 'true') {
58500                 behavior.startWalkthrough = true;
58501               }
58502
58503               if (q.map) {
58504                 behavior.hadHash = true;
58505               }
58506
58507               hashchange();
58508               updateTitle(false);
58509             }
58510           }
58511
58512           behavior.off = function () {
58513             _throttledUpdate.cancel();
58514
58515             _throttledUpdateTitle.cancel();
58516
58517             context.map().on('move.behaviorHash', null);
58518             context.on('enter.behaviorHash', null);
58519             select(window).on('hashchange.behaviorHash', null);
58520             window.location.hash = '';
58521           };
58522
58523           return behavior;
58524         }
58525
58526         /*
58527             iD.coreDifference represents the difference between two graphs.
58528             It knows how to calculate the set of entities that were
58529             created, modified, or deleted, and also contains the logic
58530             for recursively extending a difference to the complete set
58531             of entities that will require a redraw, taking into account
58532             child and parent relationships.
58533          */
58534
58535         function coreDifference(base, head) {
58536           var _changes = {};
58537           var _didChange = {}; // 'addition', 'deletion', 'geometry', 'properties'
58538
58539           var _diff = {};
58540
58541           function checkEntityID(id) {
58542             var h = head.entities[id];
58543             var b = base.entities[id];
58544             if (h === b) return;
58545             if (_changes[id]) return;
58546
58547             if (!h && b) {
58548               _changes[id] = {
58549                 base: b,
58550                 head: h
58551               };
58552               _didChange.deletion = true;
58553               return;
58554             }
58555
58556             if (h && !b) {
58557               _changes[id] = {
58558                 base: b,
58559                 head: h
58560               };
58561               _didChange.addition = true;
58562               return;
58563             }
58564
58565             if (h && b) {
58566               if (h.members && b.members && !fastDeepEqual(h.members, b.members)) {
58567                 _changes[id] = {
58568                   base: b,
58569                   head: h
58570                 };
58571                 _didChange.geometry = true;
58572                 _didChange.properties = true;
58573                 return;
58574               }
58575
58576               if (h.loc && b.loc && !geoVecEqual(h.loc, b.loc)) {
58577                 _changes[id] = {
58578                   base: b,
58579                   head: h
58580                 };
58581                 _didChange.geometry = true;
58582               }
58583
58584               if (h.nodes && b.nodes && !fastDeepEqual(h.nodes, b.nodes)) {
58585                 _changes[id] = {
58586                   base: b,
58587                   head: h
58588                 };
58589                 _didChange.geometry = true;
58590               }
58591
58592               if (h.tags && b.tags && !fastDeepEqual(h.tags, b.tags)) {
58593                 _changes[id] = {
58594                   base: b,
58595                   head: h
58596                 };
58597                 _didChange.properties = true;
58598               }
58599             }
58600           }
58601
58602           function load() {
58603             // HOT CODE: there can be many thousands of downloaded entities, so looping
58604             // through them all can become a performance bottleneck. Optimize by
58605             // resolving duplicates and using a basic `for` loop
58606             var ids = utilArrayUniq(Object.keys(head.entities).concat(Object.keys(base.entities)));
58607
58608             for (var i = 0; i < ids.length; i++) {
58609               checkEntityID(ids[i]);
58610             }
58611           }
58612
58613           load();
58614
58615           _diff.length = function length() {
58616             return Object.keys(_changes).length;
58617           };
58618
58619           _diff.changes = function changes() {
58620             return _changes;
58621           };
58622
58623           _diff.didChange = _didChange; // pass true to include affected relation members
58624
58625           _diff.extantIDs = function extantIDs(includeRelMembers) {
58626             var result = new Set();
58627             Object.keys(_changes).forEach(function (id) {
58628               if (_changes[id].head) {
58629                 result.add(id);
58630               }
58631
58632               var h = _changes[id].head;
58633               var b = _changes[id].base;
58634               var entity = h || b;
58635
58636               if (includeRelMembers && entity.type === 'relation') {
58637                 var mh = h ? h.members.map(function (m) {
58638                   return m.id;
58639                 }) : [];
58640                 var mb = b ? b.members.map(function (m) {
58641                   return m.id;
58642                 }) : [];
58643                 utilArrayUnion(mh, mb).forEach(function (memberID) {
58644                   if (head.hasEntity(memberID)) {
58645                     result.add(memberID);
58646                   }
58647                 });
58648               }
58649             });
58650             return Array.from(result);
58651           };
58652
58653           _diff.modified = function modified() {
58654             var result = [];
58655             Object.values(_changes).forEach(function (change) {
58656               if (change.base && change.head) {
58657                 result.push(change.head);
58658               }
58659             });
58660             return result;
58661           };
58662
58663           _diff.created = function created() {
58664             var result = [];
58665             Object.values(_changes).forEach(function (change) {
58666               if (!change.base && change.head) {
58667                 result.push(change.head);
58668               }
58669             });
58670             return result;
58671           };
58672
58673           _diff.deleted = function deleted() {
58674             var result = [];
58675             Object.values(_changes).forEach(function (change) {
58676               if (change.base && !change.head) {
58677                 result.push(change.base);
58678               }
58679             });
58680             return result;
58681           };
58682
58683           _diff.summary = function summary() {
58684             var relevant = {};
58685             var keys = Object.keys(_changes);
58686
58687             for (var i = 0; i < keys.length; i++) {
58688               var change = _changes[keys[i]];
58689
58690               if (change.head && change.head.geometry(head) !== 'vertex') {
58691                 addEntity(change.head, head, change.base ? 'modified' : 'created');
58692               } else if (change.base && change.base.geometry(base) !== 'vertex') {
58693                 addEntity(change.base, base, 'deleted');
58694               } else if (change.base && change.head) {
58695                 // modified vertex
58696                 var moved = !fastDeepEqual(change.base.loc, change.head.loc);
58697                 var retagged = !fastDeepEqual(change.base.tags, change.head.tags);
58698
58699                 if (moved) {
58700                   addParents(change.head);
58701                 }
58702
58703                 if (retagged || moved && change.head.hasInterestingTags()) {
58704                   addEntity(change.head, head, 'modified');
58705                 }
58706               } else if (change.head && change.head.hasInterestingTags()) {
58707                 // created vertex
58708                 addEntity(change.head, head, 'created');
58709               } else if (change.base && change.base.hasInterestingTags()) {
58710                 // deleted vertex
58711                 addEntity(change.base, base, 'deleted');
58712               }
58713             }
58714
58715             return Object.values(relevant);
58716
58717             function addEntity(entity, graph, changeType) {
58718               relevant[entity.id] = {
58719                 entity: entity,
58720                 graph: graph,
58721                 changeType: changeType
58722               };
58723             }
58724
58725             function addParents(entity) {
58726               var parents = head.parentWays(entity);
58727
58728               for (var j = parents.length - 1; j >= 0; j--) {
58729                 var parent = parents[j];
58730
58731                 if (!(parent.id in relevant)) {
58732                   addEntity(parent, head, 'modified');
58733                 }
58734               }
58735             }
58736           }; // returns complete set of entities that require a redraw
58737           //  (optionally within given `extent`)
58738
58739
58740           _diff.complete = function complete(extent) {
58741             var result = {};
58742             var id, change;
58743
58744             for (id in _changes) {
58745               change = _changes[id];
58746               var h = change.head;
58747               var b = change.base;
58748               var entity = h || b;
58749               var i;
58750               if (extent && (!h || !h.intersects(extent, head)) && (!b || !b.intersects(extent, base))) continue;
58751               result[id] = h;
58752
58753               if (entity.type === 'way') {
58754                 var nh = h ? h.nodes : [];
58755                 var nb = b ? b.nodes : [];
58756                 var diff;
58757                 diff = utilArrayDifference(nh, nb);
58758
58759                 for (i = 0; i < diff.length; i++) {
58760                   result[diff[i]] = head.hasEntity(diff[i]);
58761                 }
58762
58763                 diff = utilArrayDifference(nb, nh);
58764
58765                 for (i = 0; i < diff.length; i++) {
58766                   result[diff[i]] = head.hasEntity(diff[i]);
58767                 }
58768               }
58769
58770               if (entity.type === 'relation' && entity.isMultipolygon()) {
58771                 var mh = h ? h.members.map(function (m) {
58772                   return m.id;
58773                 }) : [];
58774                 var mb = b ? b.members.map(function (m) {
58775                   return m.id;
58776                 }) : [];
58777                 var ids = utilArrayUnion(mh, mb);
58778
58779                 for (i = 0; i < ids.length; i++) {
58780                   var member = head.hasEntity(ids[i]);
58781                   if (!member) continue; // not downloaded
58782
58783                   if (extent && !member.intersects(extent, head)) continue; // not visible
58784
58785                   result[ids[i]] = member;
58786                 }
58787               }
58788
58789               addParents(head.parentWays(entity), result);
58790               addParents(head.parentRelations(entity), result);
58791             }
58792
58793             return result;
58794
58795             function addParents(parents, result) {
58796               for (var i = 0; i < parents.length; i++) {
58797                 var parent = parents[i];
58798                 if (parent.id in result) continue;
58799                 result[parent.id] = parent;
58800                 addParents(head.parentRelations(parent), result);
58801               }
58802             }
58803           };
58804
58805           return _diff;
58806         }
58807
58808         function coreTree(head) {
58809           // tree for entities
58810           var _rtree = new RBush();
58811
58812           var _bboxes = {}; // maintain a separate tree for granular way segments
58813
58814           var _segmentsRTree = new RBush();
58815
58816           var _segmentsBBoxes = {};
58817           var _segmentsByWayId = {};
58818           var tree = {};
58819
58820           function entityBBox(entity) {
58821             var bbox = entity.extent(head).bbox();
58822             bbox.id = entity.id;
58823             _bboxes[entity.id] = bbox;
58824             return bbox;
58825           }
58826
58827           function segmentBBox(segment) {
58828             var extent = segment.extent(head); // extent can be null if the node entities aren't in the graph for some reason
58829
58830             if (!extent) return null;
58831             var bbox = extent.bbox();
58832             bbox.segment = segment;
58833             _segmentsBBoxes[segment.id] = bbox;
58834             return bbox;
58835           }
58836
58837           function removeEntity(entity) {
58838             _rtree.remove(_bboxes[entity.id]);
58839
58840             delete _bboxes[entity.id];
58841
58842             if (_segmentsByWayId[entity.id]) {
58843               _segmentsByWayId[entity.id].forEach(function (segment) {
58844                 _segmentsRTree.remove(_segmentsBBoxes[segment.id]);
58845
58846                 delete _segmentsBBoxes[segment.id];
58847               });
58848
58849               delete _segmentsByWayId[entity.id];
58850             }
58851           }
58852
58853           function loadEntities(entities) {
58854             _rtree.load(entities.map(entityBBox));
58855
58856             var segments = [];
58857             entities.forEach(function (entity) {
58858               if (entity.segments) {
58859                 var entitySegments = entity.segments(head); // cache these to make them easy to remove later
58860
58861                 _segmentsByWayId[entity.id] = entitySegments;
58862                 segments = segments.concat(entitySegments);
58863               }
58864             });
58865             if (segments.length) _segmentsRTree.load(segments.map(segmentBBox).filter(Boolean));
58866           }
58867
58868           function updateParents(entity, insertions, memo) {
58869             head.parentWays(entity).forEach(function (way) {
58870               if (_bboxes[way.id]) {
58871                 removeEntity(way);
58872                 insertions[way.id] = way;
58873               }
58874
58875               updateParents(way, insertions, memo);
58876             });
58877             head.parentRelations(entity).forEach(function (relation) {
58878               if (memo[entity.id]) return;
58879               memo[entity.id] = true;
58880
58881               if (_bboxes[relation.id]) {
58882                 removeEntity(relation);
58883                 insertions[relation.id] = relation;
58884               }
58885
58886               updateParents(relation, insertions, memo);
58887             });
58888           }
58889
58890           tree.rebase = function (entities, force) {
58891             var insertions = {};
58892
58893             for (var i = 0; i < entities.length; i++) {
58894               var entity = entities[i];
58895               if (!entity.visible) continue;
58896
58897               if (head.entities.hasOwnProperty(entity.id) || _bboxes[entity.id]) {
58898                 if (!force) {
58899                   continue;
58900                 } else if (_bboxes[entity.id]) {
58901                   removeEntity(entity);
58902                 }
58903               }
58904
58905               insertions[entity.id] = entity;
58906               updateParents(entity, insertions, {});
58907             }
58908
58909             loadEntities(Object.values(insertions));
58910             return tree;
58911           };
58912
58913           function updateToGraph(graph) {
58914             if (graph === head) return;
58915             var diff = coreDifference(head, graph);
58916             head = graph;
58917             var changed = diff.didChange;
58918             if (!changed.addition && !changed.deletion && !changed.geometry) return;
58919             var insertions = {};
58920
58921             if (changed.deletion) {
58922               diff.deleted().forEach(function (entity) {
58923                 removeEntity(entity);
58924               });
58925             }
58926
58927             if (changed.geometry) {
58928               diff.modified().forEach(function (entity) {
58929                 removeEntity(entity);
58930                 insertions[entity.id] = entity;
58931                 updateParents(entity, insertions, {});
58932               });
58933             }
58934
58935             if (changed.addition) {
58936               diff.created().forEach(function (entity) {
58937                 insertions[entity.id] = entity;
58938               });
58939             }
58940
58941             loadEntities(Object.values(insertions));
58942           } // returns an array of entities with bounding boxes overlapping `extent` for the given `graph`
58943
58944
58945           tree.intersects = function (extent, graph) {
58946             updateToGraph(graph);
58947             return _rtree.search(extent.bbox()).map(function (bbox) {
58948               return graph.entity(bbox.id);
58949             });
58950           }; // returns an array of segment objects with bounding boxes overlapping `extent` for the given `graph`
58951
58952
58953           tree.waySegments = function (extent, graph) {
58954             updateToGraph(graph);
58955             return _segmentsRTree.search(extent.bbox()).map(function (bbox) {
58956               return bbox.segment;
58957             });
58958           };
58959
58960           return tree;
58961         }
58962
58963         function uiModal(selection, blocking) {
58964           var _this = this;
58965
58966           var keybinding = utilKeybinding('modal');
58967           var previous = selection.select('div.modal');
58968           var animate = previous.empty();
58969           previous.transition().duration(200).style('opacity', 0).remove();
58970           var shaded = selection.append('div').attr('class', 'shaded').style('opacity', 0);
58971
58972           shaded.close = function () {
58973             shaded.transition().duration(200).style('opacity', 0).remove();
58974             modal.transition().duration(200).style('top', '0px');
58975             select(document).call(keybinding.unbind);
58976           };
58977
58978           var modal = shaded.append('div').attr('class', 'modal fillL');
58979           modal.append('input').attr('class', 'keytrap keytrap-first').on('focus.keytrap', moveFocusToLast);
58980
58981           if (!blocking) {
58982             shaded.on('click.remove-modal', function (d3_event) {
58983               if (d3_event.target === _this) {
58984                 shaded.close();
58985               }
58986             });
58987             modal.append('button').attr('class', 'close').on('click', shaded.close).call(svgIcon('#iD-icon-close'));
58988             keybinding.on('⌫', shaded.close).on('⎋', shaded.close);
58989             select(document).call(keybinding);
58990           }
58991
58992           modal.append('div').attr('class', 'content');
58993           modal.append('input').attr('class', 'keytrap keytrap-last').on('focus.keytrap', moveFocusToFirst);
58994
58995           if (animate) {
58996             shaded.transition().style('opacity', 1);
58997           } else {
58998             shaded.style('opacity', 1);
58999           }
59000
59001           return shaded;
59002
59003           function moveFocusToFirst() {
59004             var node = modal // there are additional rules about what's focusable, but this suits our purposes
59005             .select('a, button, input:not(.keytrap), select, textarea').node();
59006
59007             if (node) {
59008               node.focus();
59009             } else {
59010               select(this).node().blur();
59011             }
59012           }
59013
59014           function moveFocusToLast() {
59015             var nodes = modal.selectAll('a, button, input:not(.keytrap), select, textarea').nodes();
59016
59017             if (nodes.length) {
59018               nodes[nodes.length - 1].focus();
59019             } else {
59020               select(this).node().blur();
59021             }
59022           }
59023         }
59024
59025         function uiLoading(context) {
59026           var _modalSelection = select(null);
59027
59028           var _message = '';
59029           var _blocking = false;
59030
59031           var loading = function loading(selection) {
59032             _modalSelection = uiModal(selection, _blocking);
59033
59034             var loadertext = _modalSelection.select('.content').classed('loading-modal', true).append('div').attr('class', 'modal-section fillL');
59035
59036             loadertext.append('img').attr('class', 'loader').attr('src', context.imagePath('loader-white.gif'));
59037             loadertext.append('h3').html(_message);
59038
59039             _modalSelection.select('button.close').attr('class', 'hide');
59040
59041             return loading;
59042           };
59043
59044           loading.message = function (val) {
59045             if (!arguments.length) return _message;
59046             _message = val;
59047             return loading;
59048           };
59049
59050           loading.blocking = function (val) {
59051             if (!arguments.length) return _blocking;
59052             _blocking = val;
59053             return loading;
59054           };
59055
59056           loading.close = function () {
59057             _modalSelection.remove();
59058           };
59059
59060           loading.isShown = function () {
59061             return _modalSelection && !_modalSelection.empty() && _modalSelection.node().parentNode;
59062           };
59063
59064           return loading;
59065         }
59066
59067         function coreHistory(context) {
59068           var dispatch$1 = dispatch('reset', 'change', 'merge', 'restore', 'undone', 'redone');
59069
59070           var _lock = utilSessionMutex('lock'); // restorable if iD not open in another window/tab and a saved history exists in localStorage
59071
59072
59073           var _hasUnresolvedRestorableChanges = _lock.lock() && !!corePreferences(getKey('saved_history'));
59074
59075           var duration = 150;
59076           var _imageryUsed = [];
59077           var _photoOverlaysUsed = [];
59078           var _checkpoints = {};
59079
59080           var _pausedGraph;
59081
59082           var _stack;
59083
59084           var _index;
59085
59086           var _tree; // internal _act, accepts list of actions and eased time
59087
59088
59089           function _act(actions, t) {
59090             actions = Array.prototype.slice.call(actions);
59091             var annotation;
59092
59093             if (typeof actions[actions.length - 1] !== 'function') {
59094               annotation = actions.pop();
59095             }
59096
59097             var graph = _stack[_index].graph;
59098
59099             for (var i = 0; i < actions.length; i++) {
59100               graph = actions[i](graph, t);
59101             }
59102
59103             return {
59104               graph: graph,
59105               annotation: annotation,
59106               imageryUsed: _imageryUsed,
59107               photoOverlaysUsed: _photoOverlaysUsed,
59108               transform: context.projection.transform(),
59109               selectedIDs: context.selectedIDs()
59110             };
59111           } // internal _perform with eased time
59112
59113
59114           function _perform(args, t) {
59115             var previous = _stack[_index].graph;
59116             _stack = _stack.slice(0, _index + 1);
59117
59118             var actionResult = _act(args, t);
59119
59120             _stack.push(actionResult);
59121
59122             _index++;
59123             return change(previous);
59124           } // internal _replace with eased time
59125
59126
59127           function _replace(args, t) {
59128             var previous = _stack[_index].graph; // assert(_index == _stack.length - 1)
59129
59130             var actionResult = _act(args, t);
59131
59132             _stack[_index] = actionResult;
59133             return change(previous);
59134           } // internal _overwrite with eased time
59135
59136
59137           function _overwrite(args, t) {
59138             var previous = _stack[_index].graph;
59139
59140             if (_index > 0) {
59141               _index--;
59142
59143               _stack.pop();
59144             }
59145
59146             _stack = _stack.slice(0, _index + 1);
59147
59148             var actionResult = _act(args, t);
59149
59150             _stack.push(actionResult);
59151
59152             _index++;
59153             return change(previous);
59154           } // determine difference and dispatch a change event
59155
59156
59157           function change(previous) {
59158             var difference = coreDifference(previous, history.graph());
59159
59160             if (!_pausedGraph) {
59161               dispatch$1.call('change', this, difference);
59162             }
59163
59164             return difference;
59165           } // iD uses namespaced keys so multiple installations do not conflict
59166
59167
59168           function getKey(n) {
59169             return 'iD_' + window.location.origin + '_' + n;
59170           }
59171
59172           var history = {
59173             graph: function graph() {
59174               return _stack[_index].graph;
59175             },
59176             tree: function tree() {
59177               return _tree;
59178             },
59179             base: function base() {
59180               return _stack[0].graph;
59181             },
59182             merge: function merge(entities
59183             /*, extent*/
59184             ) {
59185               var stack = _stack.map(function (state) {
59186                 return state.graph;
59187               });
59188
59189               _stack[0].graph.rebase(entities, stack, false);
59190
59191               _tree.rebase(entities, false);
59192
59193               dispatch$1.call('merge', this, entities);
59194             },
59195             perform: function perform() {
59196               // complete any transition already in progress
59197               select(document).interrupt('history.perform');
59198               var transitionable = false;
59199               var action0 = arguments[0];
59200
59201               if (arguments.length === 1 || arguments.length === 2 && typeof arguments[1] !== 'function') {
59202                 transitionable = !!action0.transitionable;
59203               }
59204
59205               if (transitionable) {
59206                 var origArguments = arguments;
59207                 select(document).transition('history.perform').duration(duration).ease(linear$1).tween('history.tween', function () {
59208                   return function (t) {
59209                     if (t < 1) _overwrite([action0], t);
59210                   };
59211                 }).on('start', function () {
59212                   _perform([action0], 0);
59213                 }).on('end interrupt', function () {
59214                   _overwrite(origArguments, 1);
59215                 });
59216               } else {
59217                 return _perform(arguments);
59218               }
59219             },
59220             replace: function replace() {
59221               select(document).interrupt('history.perform');
59222               return _replace(arguments, 1);
59223             },
59224             // Same as calling pop and then perform
59225             overwrite: function overwrite() {
59226               select(document).interrupt('history.perform');
59227               return _overwrite(arguments, 1);
59228             },
59229             pop: function pop(n) {
59230               select(document).interrupt('history.perform');
59231               var previous = _stack[_index].graph;
59232
59233               if (isNaN(+n) || +n < 0) {
59234                 n = 1;
59235               }
59236
59237               while (n-- > 0 && _index > 0) {
59238                 _index--;
59239
59240                 _stack.pop();
59241               }
59242
59243               return change(previous);
59244             },
59245             // Back to the previous annotated state or _index = 0.
59246             undo: function undo() {
59247               select(document).interrupt('history.perform');
59248               var previousStack = _stack[_index];
59249               var previous = previousStack.graph;
59250
59251               while (_index > 0) {
59252                 _index--;
59253                 if (_stack[_index].annotation) break;
59254               }
59255
59256               dispatch$1.call('undone', this, _stack[_index], previousStack);
59257               return change(previous);
59258             },
59259             // Forward to the next annotated state.
59260             redo: function redo() {
59261               select(document).interrupt('history.perform');
59262               var previousStack = _stack[_index];
59263               var previous = previousStack.graph;
59264               var tryIndex = _index;
59265
59266               while (tryIndex < _stack.length - 1) {
59267                 tryIndex++;
59268
59269                 if (_stack[tryIndex].annotation) {
59270                   _index = tryIndex;
59271                   dispatch$1.call('redone', this, _stack[_index], previousStack);
59272                   break;
59273                 }
59274               }
59275
59276               return change(previous);
59277             },
59278             pauseChangeDispatch: function pauseChangeDispatch() {
59279               if (!_pausedGraph) {
59280                 _pausedGraph = _stack[_index].graph;
59281               }
59282             },
59283             resumeChangeDispatch: function resumeChangeDispatch() {
59284               if (_pausedGraph) {
59285                 var previous = _pausedGraph;
59286                 _pausedGraph = null;
59287                 return change(previous);
59288               }
59289             },
59290             undoAnnotation: function undoAnnotation() {
59291               var i = _index;
59292
59293               while (i >= 0) {
59294                 if (_stack[i].annotation) return _stack[i].annotation;
59295                 i--;
59296               }
59297             },
59298             redoAnnotation: function redoAnnotation() {
59299               var i = _index + 1;
59300
59301               while (i <= _stack.length - 1) {
59302                 if (_stack[i].annotation) return _stack[i].annotation;
59303                 i++;
59304               }
59305             },
59306             // Returns the entities from the active graph with bounding boxes
59307             // overlapping the given `extent`.
59308             intersects: function intersects(extent) {
59309               return _tree.intersects(extent, _stack[_index].graph);
59310             },
59311             difference: function difference() {
59312               var base = _stack[0].graph;
59313               var head = _stack[_index].graph;
59314               return coreDifference(base, head);
59315             },
59316             changes: function changes(action) {
59317               var base = _stack[0].graph;
59318               var head = _stack[_index].graph;
59319
59320               if (action) {
59321                 head = action(head);
59322               }
59323
59324               var difference = coreDifference(base, head);
59325               return {
59326                 modified: difference.modified(),
59327                 created: difference.created(),
59328                 deleted: difference.deleted()
59329               };
59330             },
59331             hasChanges: function hasChanges() {
59332               return this.difference().length() > 0;
59333             },
59334             imageryUsed: function imageryUsed(sources) {
59335               if (sources) {
59336                 _imageryUsed = sources;
59337                 return history;
59338               } else {
59339                 var s = new Set();
59340
59341                 _stack.slice(1, _index + 1).forEach(function (state) {
59342                   state.imageryUsed.forEach(function (source) {
59343                     if (source !== 'Custom') {
59344                       s.add(source);
59345                     }
59346                   });
59347                 });
59348
59349                 return Array.from(s);
59350               }
59351             },
59352             photoOverlaysUsed: function photoOverlaysUsed(sources) {
59353               if (sources) {
59354                 _photoOverlaysUsed = sources;
59355                 return history;
59356               } else {
59357                 var s = new Set();
59358
59359                 _stack.slice(1, _index + 1).forEach(function (state) {
59360                   if (state.photoOverlaysUsed && Array.isArray(state.photoOverlaysUsed)) {
59361                     state.photoOverlaysUsed.forEach(function (photoOverlay) {
59362                       s.add(photoOverlay);
59363                     });
59364                   }
59365                 });
59366
59367                 return Array.from(s);
59368               }
59369             },
59370             // save the current history state
59371             checkpoint: function checkpoint(key) {
59372               _checkpoints[key] = {
59373                 stack: _stack,
59374                 index: _index
59375               };
59376               return history;
59377             },
59378             // restore history state to a given checkpoint or reset completely
59379             reset: function reset(key) {
59380               if (key !== undefined && _checkpoints.hasOwnProperty(key)) {
59381                 _stack = _checkpoints[key].stack;
59382                 _index = _checkpoints[key].index;
59383               } else {
59384                 _stack = [{
59385                   graph: coreGraph()
59386                 }];
59387                 _index = 0;
59388                 _tree = coreTree(_stack[0].graph);
59389                 _checkpoints = {};
59390               }
59391
59392               dispatch$1.call('reset');
59393               dispatch$1.call('change');
59394               return history;
59395             },
59396             // `toIntroGraph()` is used to export the intro graph used by the walkthrough.
59397             //
59398             // To use it:
59399             //  1. Start the walkthrough.
59400             //  2. Get to a "free editing" tutorial step
59401             //  3. Make your edits to the walkthrough map
59402             //  4. In your browser dev console run:
59403             //        `id.history().toIntroGraph()`
59404             //  5. This outputs stringified JSON to the browser console
59405             //  6. Copy it to `data/intro_graph.json` and prettify it in your code editor
59406             toIntroGraph: function toIntroGraph() {
59407               var nextID = {
59408                 n: 0,
59409                 r: 0,
59410                 w: 0
59411               };
59412               var permIDs = {};
59413               var graph = this.graph();
59414               var baseEntities = {}; // clone base entities..
59415
59416               Object.values(graph.base().entities).forEach(function (entity) {
59417                 var copy = copyIntroEntity(entity);
59418                 baseEntities[copy.id] = copy;
59419               }); // replace base entities with head entities..
59420
59421               Object.keys(graph.entities).forEach(function (id) {
59422                 var entity = graph.entities[id];
59423
59424                 if (entity) {
59425                   var copy = copyIntroEntity(entity);
59426                   baseEntities[copy.id] = copy;
59427                 } else {
59428                   delete baseEntities[id];
59429                 }
59430               }); // swap temporary for permanent ids..
59431
59432               Object.values(baseEntities).forEach(function (entity) {
59433                 if (Array.isArray(entity.nodes)) {
59434                   entity.nodes = entity.nodes.map(function (node) {
59435                     return permIDs[node] || node;
59436                   });
59437                 }
59438
59439                 if (Array.isArray(entity.members)) {
59440                   entity.members = entity.members.map(function (member) {
59441                     member.id = permIDs[member.id] || member.id;
59442                     return member;
59443                   });
59444                 }
59445               });
59446               return JSON.stringify({
59447                 dataIntroGraph: baseEntities
59448               });
59449
59450               function copyIntroEntity(source) {
59451                 var copy = utilObjectOmit(source, ['type', 'user', 'v', 'version', 'visible']); // Note: the copy is no longer an osmEntity, so it might not have `tags`
59452
59453                 if (copy.tags && !Object.keys(copy.tags)) {
59454                   delete copy.tags;
59455                 }
59456
59457                 if (Array.isArray(copy.loc)) {
59458                   copy.loc[0] = +copy.loc[0].toFixed(6);
59459                   copy.loc[1] = +copy.loc[1].toFixed(6);
59460                 }
59461
59462                 var match = source.id.match(/([nrw])-\d*/); // temporary id
59463
59464                 if (match !== null) {
59465                   var nrw = match[1];
59466                   var permID;
59467
59468                   do {
59469                     permID = nrw + ++nextID[nrw];
59470                   } while (baseEntities.hasOwnProperty(permID));
59471
59472                   copy.id = permIDs[source.id] = permID;
59473                 }
59474
59475                 return copy;
59476               }
59477             },
59478             toJSON: function toJSON() {
59479               if (!this.hasChanges()) return;
59480               var allEntities = {};
59481               var baseEntities = {};
59482               var base = _stack[0];
59483
59484               var s = _stack.map(function (i) {
59485                 var modified = [];
59486                 var deleted = [];
59487                 Object.keys(i.graph.entities).forEach(function (id) {
59488                   var entity = i.graph.entities[id];
59489
59490                   if (entity) {
59491                     var key = osmEntity.key(entity);
59492                     allEntities[key] = entity;
59493                     modified.push(key);
59494                   } else {
59495                     deleted.push(id);
59496                   } // make sure that the originals of changed or deleted entities get merged
59497                   // into the base of the _stack after restoring the data from JSON.
59498
59499
59500                   if (id in base.graph.entities) {
59501                     baseEntities[id] = base.graph.entities[id];
59502                   }
59503
59504                   if (entity && entity.nodes) {
59505                     // get originals of pre-existing child nodes
59506                     entity.nodes.forEach(function (nodeID) {
59507                       if (nodeID in base.graph.entities) {
59508                         baseEntities[nodeID] = base.graph.entities[nodeID];
59509                       }
59510                     });
59511                   } // get originals of parent entities too
59512
59513
59514                   var baseParents = base.graph._parentWays[id];
59515
59516                   if (baseParents) {
59517                     baseParents.forEach(function (parentID) {
59518                       if (parentID in base.graph.entities) {
59519                         baseEntities[parentID] = base.graph.entities[parentID];
59520                       }
59521                     });
59522                   }
59523                 });
59524                 var x = {};
59525                 if (modified.length) x.modified = modified;
59526                 if (deleted.length) x.deleted = deleted;
59527                 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
59528                 if (i.photoOverlaysUsed) x.photoOverlaysUsed = i.photoOverlaysUsed;
59529                 if (i.annotation) x.annotation = i.annotation;
59530                 if (i.transform) x.transform = i.transform;
59531                 if (i.selectedIDs) x.selectedIDs = i.selectedIDs;
59532                 return x;
59533               });
59534
59535               return JSON.stringify({
59536                 version: 3,
59537                 entities: Object.values(allEntities),
59538                 baseEntities: Object.values(baseEntities),
59539                 stack: s,
59540                 nextIDs: osmEntity.id.next,
59541                 index: _index,
59542                 // note the time the changes were saved
59543                 timestamp: new Date().getTime()
59544               });
59545             },
59546             fromJSON: function fromJSON(json, loadChildNodes) {
59547               var h = JSON.parse(json);
59548               var loadComplete = true;
59549               osmEntity.id.next = h.nextIDs;
59550               _index = h.index;
59551
59552               if (h.version === 2 || h.version === 3) {
59553                 var allEntities = {};
59554                 h.entities.forEach(function (entity) {
59555                   allEntities[osmEntity.key(entity)] = osmEntity(entity);
59556                 });
59557
59558                 if (h.version === 3) {
59559                   // This merges originals for changed entities into the base of
59560                   // the _stack even if the current _stack doesn't have them (for
59561                   // example when iD has been restarted in a different region)
59562                   var baseEntities = h.baseEntities.map(function (d) {
59563                     return osmEntity(d);
59564                   });
59565
59566                   var stack = _stack.map(function (state) {
59567                     return state.graph;
59568                   });
59569
59570                   _stack[0].graph.rebase(baseEntities, stack, true);
59571
59572                   _tree.rebase(baseEntities, true); // When we restore a modified way, we also need to fetch any missing
59573                   // childnodes that would normally have been downloaded with it.. #2142
59574
59575
59576                   if (loadChildNodes) {
59577                     var osm = context.connection();
59578                     var baseWays = baseEntities.filter(function (e) {
59579                       return e.type === 'way';
59580                     });
59581                     var nodeIDs = baseWays.reduce(function (acc, way) {
59582                       return utilArrayUnion(acc, way.nodes);
59583                     }, []);
59584                     var missing = nodeIDs.filter(function (n) {
59585                       return !_stack[0].graph.hasEntity(n);
59586                     });
59587
59588                     if (missing.length && osm) {
59589                       loadComplete = false;
59590                       context.map().redrawEnable(false);
59591                       var loading = uiLoading(context).blocking(true);
59592                       context.container().call(loading);
59593
59594                       var childNodesLoaded = function childNodesLoaded(err, result) {
59595                         if (!err) {
59596                           var visibleGroups = utilArrayGroupBy(result.data, 'visible');
59597                           var visibles = visibleGroups["true"] || []; // alive nodes
59598
59599                           var invisibles = visibleGroups["false"] || []; // deleted nodes
59600
59601                           if (visibles.length) {
59602                             var visibleIDs = visibles.map(function (entity) {
59603                               return entity.id;
59604                             });
59605
59606                             var stack = _stack.map(function (state) {
59607                               return state.graph;
59608                             });
59609
59610                             missing = utilArrayDifference(missing, visibleIDs);
59611
59612                             _stack[0].graph.rebase(visibles, stack, true);
59613
59614                             _tree.rebase(visibles, true);
59615                           } // fetch older versions of nodes that were deleted..
59616
59617
59618                           invisibles.forEach(function (entity) {
59619                             osm.loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
59620                           });
59621                         }
59622
59623                         if (err || !missing.length) {
59624                           loading.close();
59625                           context.map().redrawEnable(true);
59626                           dispatch$1.call('change');
59627                           dispatch$1.call('restore', this);
59628                         }
59629                       };
59630
59631                       osm.loadMultiple(missing, childNodesLoaded);
59632                     }
59633                   }
59634                 }
59635
59636                 _stack = h.stack.map(function (d) {
59637                   var entities = {},
59638                       entity;
59639
59640                   if (d.modified) {
59641                     d.modified.forEach(function (key) {
59642                       entity = allEntities[key];
59643                       entities[entity.id] = entity;
59644                     });
59645                   }
59646
59647                   if (d.deleted) {
59648                     d.deleted.forEach(function (id) {
59649                       entities[id] = undefined;
59650                     });
59651                   }
59652
59653                   return {
59654                     graph: coreGraph(_stack[0].graph).load(entities),
59655                     annotation: d.annotation,
59656                     imageryUsed: d.imageryUsed,
59657                     photoOverlaysUsed: d.photoOverlaysUsed,
59658                     transform: d.transform,
59659                     selectedIDs: d.selectedIDs
59660                   };
59661                 });
59662               } else {
59663                 // original version
59664                 _stack = h.stack.map(function (d) {
59665                   var entities = {};
59666
59667                   for (var i in d.entities) {
59668                     var entity = d.entities[i];
59669                     entities[i] = entity === 'undefined' ? undefined : osmEntity(entity);
59670                   }
59671
59672                   d.graph = coreGraph(_stack[0].graph).load(entities);
59673                   return d;
59674                 });
59675               }
59676
59677               var transform = _stack[_index].transform;
59678
59679               if (transform) {
59680                 context.map().transformEase(transform, 0); // 0 = immediate, no easing
59681               }
59682
59683               if (loadComplete) {
59684                 dispatch$1.call('change');
59685                 dispatch$1.call('restore', this);
59686               }
59687
59688               return history;
59689             },
59690             lock: function lock() {
59691               return _lock.lock();
59692             },
59693             unlock: function unlock() {
59694               _lock.unlock();
59695             },
59696             save: function save() {
59697               if (_lock.locked() && // don't overwrite existing, unresolved changes
59698               !_hasUnresolvedRestorableChanges) {
59699                 corePreferences(getKey('saved_history'), history.toJSON() || null);
59700               }
59701
59702               return history;
59703             },
59704             // delete the history version saved in localStorage
59705             clearSaved: function clearSaved() {
59706               context.debouncedSave.cancel();
59707
59708               if (_lock.locked()) {
59709                 _hasUnresolvedRestorableChanges = false;
59710                 corePreferences(getKey('saved_history'), null); // clear the changeset metadata associated with the saved history
59711
59712                 corePreferences('comment', null);
59713                 corePreferences('hashtags', null);
59714                 corePreferences('source', null);
59715               }
59716
59717               return history;
59718             },
59719             savedHistoryJSON: function savedHistoryJSON() {
59720               return corePreferences(getKey('saved_history'));
59721             },
59722             hasRestorableChanges: function hasRestorableChanges() {
59723               return _hasUnresolvedRestorableChanges;
59724             },
59725             // load history from a version stored in localStorage
59726             restore: function restore() {
59727               if (_lock.locked()) {
59728                 _hasUnresolvedRestorableChanges = false;
59729                 var json = this.savedHistoryJSON();
59730                 if (json) history.fromJSON(json, true);
59731               }
59732             },
59733             _getKey: getKey
59734           };
59735           history.reset();
59736           return utilRebind(history, dispatch$1, 'on');
59737         }
59738
59739         /**
59740          * Look for roads that can be connected to other roads with a short extension
59741          */
59742
59743         function validationAlmostJunction(context) {
59744           var type = 'almost_junction';
59745           var EXTEND_TH_METERS = 5;
59746           var WELD_TH_METERS = 0.75; // Comes from considering bounding case of parallel ways
59747
59748           var CLOSE_NODE_TH = EXTEND_TH_METERS - WELD_TH_METERS; // Comes from considering bounding case of perpendicular ways
59749
59750           var SIG_ANGLE_TH = Math.atan(WELD_TH_METERS / EXTEND_TH_METERS);
59751
59752           function isHighway(entity) {
59753             return entity.type === 'way' && osmRoutableHighwayTagValues[entity.tags.highway];
59754           }
59755
59756           function isTaggedAsNotContinuing(node) {
59757             return node.tags.noexit === 'yes' || node.tags.amenity === 'parking_entrance' || node.tags.entrance && node.tags.entrance !== 'no';
59758           }
59759
59760           var validation = function checkAlmostJunction(entity, graph) {
59761             if (!isHighway(entity)) return [];
59762             if (entity.isDegenerate()) return [];
59763             var tree = context.history().tree();
59764             var extendableNodeInfos = findConnectableEndNodesByExtension(entity);
59765             var issues = [];
59766             extendableNodeInfos.forEach(function (extendableNodeInfo) {
59767               issues.push(new validationIssue({
59768                 type: type,
59769                 subtype: 'highway-highway',
59770                 severity: 'warning',
59771                 message: function message(context) {
59772                   var entity1 = context.hasEntity(this.entityIds[0]);
59773
59774                   if (this.entityIds[0] === this.entityIds[2]) {
59775                     return entity1 ? _t.html('issues.almost_junction.self.message', {
59776                       feature: utilDisplayLabel(entity1, context.graph())
59777                     }) : '';
59778                   } else {
59779                     var entity2 = context.hasEntity(this.entityIds[2]);
59780                     return entity1 && entity2 ? _t.html('issues.almost_junction.message', {
59781                       feature: utilDisplayLabel(entity1, context.graph()),
59782                       feature2: utilDisplayLabel(entity2, context.graph())
59783                     }) : '';
59784                   }
59785                 },
59786                 reference: showReference,
59787                 entityIds: [entity.id, extendableNodeInfo.node.id, extendableNodeInfo.wid],
59788                 loc: extendableNodeInfo.node.loc,
59789                 hash: JSON.stringify(extendableNodeInfo.node.loc),
59790                 data: {
59791                   midId: extendableNodeInfo.mid.id,
59792                   edge: extendableNodeInfo.edge,
59793                   cross_loc: extendableNodeInfo.cross_loc
59794                 },
59795                 dynamicFixes: makeFixes
59796               }));
59797             });
59798             return issues;
59799
59800             function makeFixes(context) {
59801               var fixes = [new validationIssueFix({
59802                 icon: 'iD-icon-abutment',
59803                 title: _t.html('issues.fix.connect_features.title'),
59804                 onClick: function onClick(context) {
59805                   var annotation = _t('issues.fix.connect_almost_junction.annotation');
59806
59807                   var _this$issue$entityIds = _slicedToArray(this.issue.entityIds, 3),
59808                       endNodeId = _this$issue$entityIds[1],
59809                       crossWayId = _this$issue$entityIds[2];
59810
59811                   var midNode = context.entity(this.issue.data.midId);
59812                   var endNode = context.entity(endNodeId);
59813                   var crossWay = context.entity(crossWayId); // When endpoints are close, just join if resulting small change in angle (#7201)
59814
59815                   var nearEndNodes = findNearbyEndNodes(endNode, crossWay);
59816
59817                   if (nearEndNodes.length > 0) {
59818                     var collinear = findSmallJoinAngle(midNode, endNode, nearEndNodes);
59819
59820                     if (collinear) {
59821                       context.perform(actionMergeNodes([collinear.id, endNode.id], collinear.loc), annotation);
59822                       return;
59823                     }
59824                   }
59825
59826                   var targetEdge = this.issue.data.edge;
59827                   var crossLoc = this.issue.data.cross_loc;
59828                   var edgeNodes = [context.entity(targetEdge[0]), context.entity(targetEdge[1])];
59829                   var closestNodeInfo = geoSphericalClosestNode(edgeNodes, crossLoc); // already a point nearby, just connect to that
59830
59831                   if (closestNodeInfo.distance < WELD_TH_METERS) {
59832                     context.perform(actionMergeNodes([closestNodeInfo.node.id, endNode.id], closestNodeInfo.node.loc), annotation); // else add the end node to the edge way
59833                   } else {
59834                     context.perform(actionAddMidpoint({
59835                       loc: crossLoc,
59836                       edge: targetEdge
59837                     }, endNode), annotation);
59838                   }
59839                 }
59840               })];
59841               var node = context.hasEntity(this.entityIds[1]);
59842
59843               if (node && !node.hasInterestingTags()) {
59844                 // node has no descriptive tags, suggest noexit fix
59845                 fixes.push(new validationIssueFix({
59846                   icon: 'maki-barrier',
59847                   title: _t.html('issues.fix.tag_as_disconnected.title'),
59848                   onClick: function onClick(context) {
59849                     var nodeID = this.issue.entityIds[1];
59850                     var tags = Object.assign({}, context.entity(nodeID).tags);
59851                     tags.noexit = 'yes';
59852                     context.perform(actionChangeTags(nodeID, tags), _t('issues.fix.tag_as_disconnected.annotation'));
59853                   }
59854                 }));
59855               }
59856
59857               return fixes;
59858             }
59859
59860             function showReference(selection) {
59861               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.almost_junction.highway-highway.reference'));
59862             }
59863
59864             function isExtendableCandidate(node, way) {
59865               // can not accurately test vertices on tiles not downloaded from osm - #5938
59866               var osm = services.osm;
59867
59868               if (osm && !osm.isDataLoaded(node.loc)) {
59869                 return false;
59870               }
59871
59872               if (isTaggedAsNotContinuing(node) || graph.parentWays(node).length !== 1) {
59873                 return false;
59874               }
59875
59876               var occurrences = 0;
59877
59878               for (var index in way.nodes) {
59879                 if (way.nodes[index] === node.id) {
59880                   occurrences += 1;
59881
59882                   if (occurrences > 1) {
59883                     return false;
59884                   }
59885                 }
59886               }
59887
59888               return true;
59889             }
59890
59891             function findConnectableEndNodesByExtension(way) {
59892               var results = [];
59893               if (way.isClosed()) return results;
59894               var testNodes;
59895               var indices = [0, way.nodes.length - 1];
59896               indices.forEach(function (nodeIndex) {
59897                 var nodeID = way.nodes[nodeIndex];
59898                 var node = graph.entity(nodeID);
59899                 if (!isExtendableCandidate(node, way)) return;
59900                 var connectionInfo = canConnectByExtend(way, nodeIndex);
59901                 if (!connectionInfo) return;
59902                 testNodes = graph.childNodes(way).slice(); // shallow copy
59903
59904                 testNodes[nodeIndex] = testNodes[nodeIndex].move(connectionInfo.cross_loc); // don't flag issue if connecting the ways would cause self-intersection
59905
59906                 if (geoHasSelfIntersections(testNodes, nodeID)) return;
59907                 results.push(connectionInfo);
59908               });
59909               return results;
59910             }
59911
59912             function findNearbyEndNodes(node, way) {
59913               return [way.nodes[0], way.nodes[way.nodes.length - 1]].map(function (d) {
59914                 return graph.entity(d);
59915               }).filter(function (d) {
59916                 // Node cannot be near to itself, but other endnode of same way could be
59917                 return d.id !== node.id && geoSphericalDistance(node.loc, d.loc) <= CLOSE_NODE_TH;
59918               });
59919             }
59920
59921             function findSmallJoinAngle(midNode, tipNode, endNodes) {
59922               // Both nodes could be close, so want to join whichever is closest to collinear
59923               var joinTo;
59924               var minAngle = Infinity; // Checks midNode -> tipNode -> endNode for collinearity
59925
59926               endNodes.forEach(function (endNode) {
59927                 var a1 = geoAngle(midNode, tipNode, context.projection) + Math.PI;
59928                 var a2 = geoAngle(midNode, endNode, context.projection) + Math.PI;
59929                 var diff = Math.max(a1, a2) - Math.min(a1, a2);
59930
59931                 if (diff < minAngle) {
59932                   joinTo = endNode;
59933                   minAngle = diff;
59934                 }
59935               });
59936               /* Threshold set by considering right angle triangle
59937               based on node joining threshold and extension distance */
59938
59939               if (minAngle <= SIG_ANGLE_TH) return joinTo;
59940               return null;
59941             }
59942
59943             function hasTag(tags, key) {
59944               return tags[key] !== undefined && tags[key] !== 'no';
59945             }
59946
59947             function canConnectWays(way, way2) {
59948               // allow self-connections
59949               if (way.id === way2.id) return true; // if one is bridge or tunnel, both must be bridge or tunnel
59950
59951               if ((hasTag(way.tags, 'bridge') || hasTag(way2.tags, 'bridge')) && !(hasTag(way.tags, 'bridge') && hasTag(way2.tags, 'bridge'))) return false;
59952               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
59953
59954               var layer1 = way.tags.layer || '0',
59955                   layer2 = way2.tags.layer || '0';
59956               if (layer1 !== layer2) return false;
59957               var level1 = way.tags.level || '0',
59958                   level2 = way2.tags.level || '0';
59959               if (level1 !== level2) return false;
59960               return true;
59961             }
59962
59963             function canConnectByExtend(way, endNodeIdx) {
59964               var tipNid = way.nodes[endNodeIdx]; // the 'tip' node for extension point
59965
59966               var midNid = endNodeIdx === 0 ? way.nodes[1] : way.nodes[way.nodes.length - 2]; // the other node of the edge
59967
59968               var tipNode = graph.entity(tipNid);
59969               var midNode = graph.entity(midNid);
59970               var lon = tipNode.loc[0];
59971               var lat = tipNode.loc[1];
59972               var lon_range = geoMetersToLon(EXTEND_TH_METERS, lat) / 2;
59973               var lat_range = geoMetersToLat(EXTEND_TH_METERS) / 2;
59974               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
59975
59976               var edgeLen = geoSphericalDistance(midNode.loc, tipNode.loc);
59977               var t = EXTEND_TH_METERS / edgeLen + 1.0;
59978               var extTipLoc = geoVecInterp(midNode.loc, tipNode.loc, t); // then, check if the extension part [tipNode.loc -> extTipLoc] intersects any other ways
59979
59980               var segmentInfos = tree.waySegments(queryExtent, graph);
59981
59982               for (var i = 0; i < segmentInfos.length; i++) {
59983                 var segmentInfo = segmentInfos[i];
59984                 var way2 = graph.entity(segmentInfo.wayId);
59985                 if (!isHighway(way2)) continue;
59986                 if (!canConnectWays(way, way2)) continue;
59987                 var nAid = segmentInfo.nodes[0],
59988                     nBid = segmentInfo.nodes[1];
59989                 if (nAid === tipNid || nBid === tipNid) continue;
59990                 var nA = graph.entity(nAid),
59991                     nB = graph.entity(nBid);
59992                 var crossLoc = geoLineIntersection([tipNode.loc, extTipLoc], [nA.loc, nB.loc]);
59993
59994                 if (crossLoc) {
59995                   return {
59996                     mid: midNode,
59997                     node: tipNode,
59998                     wid: way2.id,
59999                     edge: [nA.id, nB.id],
60000                     cross_loc: crossLoc
60001                   };
60002                 }
60003               }
60004
60005               return null;
60006             }
60007           };
60008
60009           validation.type = type;
60010           return validation;
60011         }
60012
60013         function validationCloseNodes(context) {
60014           var type = 'close_nodes';
60015           var pointThresholdMeters = 0.2;
60016
60017           var validation = function validation(entity, graph) {
60018             if (entity.type === 'node') {
60019               return getIssuesForNode(entity);
60020             } else if (entity.type === 'way') {
60021               return getIssuesForWay(entity);
60022             }
60023
60024             return [];
60025
60026             function getIssuesForNode(node) {
60027               var parentWays = graph.parentWays(node);
60028
60029               if (parentWays.length) {
60030                 return getIssuesForVertex(node, parentWays);
60031               } else {
60032                 return getIssuesForDetachedPoint(node);
60033               }
60034             }
60035
60036             function wayTypeFor(way) {
60037               if (way.tags.boundary && way.tags.boundary !== 'no') return 'boundary';
60038               if (way.tags.indoor && way.tags.indoor !== 'no') return 'indoor';
60039               if (way.tags.building && way.tags.building !== 'no' || way.tags['building:part'] && way.tags['building:part'] !== 'no') return 'building';
60040               if (osmPathHighwayTagValues[way.tags.highway]) return 'path';
60041               var parentRelations = graph.parentRelations(way);
60042
60043               for (var i in parentRelations) {
60044                 var relation = parentRelations[i];
60045                 if (relation.tags.type === 'boundary') return 'boundary';
60046
60047                 if (relation.isMultipolygon()) {
60048                   if (relation.tags.indoor && relation.tags.indoor !== 'no') return 'indoor';
60049                   if (relation.tags.building && relation.tags.building !== 'no' || relation.tags['building:part'] && relation.tags['building:part'] !== 'no') return 'building';
60050                 }
60051               }
60052
60053               return 'other';
60054             }
60055
60056             function shouldCheckWay(way) {
60057               // don't flag issues where merging would create degenerate ways
60058               if (way.nodes.length <= 2 || way.isClosed() && way.nodes.length <= 4) return false;
60059               var bbox = way.extent(graph).bbox();
60060               var hypotenuseMeters = geoSphericalDistance([bbox.minX, bbox.minY], [bbox.maxX, bbox.maxY]); // don't flag close nodes in very small ways
60061
60062               if (hypotenuseMeters < 1.5) return false;
60063               return true;
60064             }
60065
60066             function getIssuesForWay(way) {
60067               if (!shouldCheckWay(way)) return [];
60068               var issues = [],
60069                   nodes = graph.childNodes(way);
60070
60071               for (var i = 0; i < nodes.length - 1; i++) {
60072                 var node1 = nodes[i];
60073                 var node2 = nodes[i + 1];
60074                 var issue = getWayIssueIfAny(node1, node2, way);
60075                 if (issue) issues.push(issue);
60076               }
60077
60078               return issues;
60079             }
60080
60081             function getIssuesForVertex(node, parentWays) {
60082               var issues = [];
60083
60084               function checkForCloseness(node1, node2, way) {
60085                 var issue = getWayIssueIfAny(node1, node2, way);
60086                 if (issue) issues.push(issue);
60087               }
60088
60089               for (var i = 0; i < parentWays.length; i++) {
60090                 var parentWay = parentWays[i];
60091                 if (!shouldCheckWay(parentWay)) continue;
60092                 var lastIndex = parentWay.nodes.length - 1;
60093
60094                 for (var j = 0; j < parentWay.nodes.length; j++) {
60095                   if (j !== 0) {
60096                     if (parentWay.nodes[j - 1] === node.id) {
60097                       checkForCloseness(node, graph.entity(parentWay.nodes[j]), parentWay);
60098                     }
60099                   }
60100
60101                   if (j !== lastIndex) {
60102                     if (parentWay.nodes[j + 1] === node.id) {
60103                       checkForCloseness(graph.entity(parentWay.nodes[j]), node, parentWay);
60104                     }
60105                   }
60106                 }
60107               }
60108
60109               return issues;
60110             }
60111
60112             function thresholdMetersForWay(way) {
60113               if (!shouldCheckWay(way)) return 0;
60114               var wayType = wayTypeFor(way); // don't flag boundaries since they might be highly detailed and can't be easily verified
60115
60116               if (wayType === 'boundary') return 0; // expect some features to be mapped with higher levels of detail
60117
60118               if (wayType === 'indoor') return 0.01;
60119               if (wayType === 'building') return 0.05;
60120               if (wayType === 'path') return 0.1;
60121               return 0.2;
60122             }
60123
60124             function getIssuesForDetachedPoint(node) {
60125               var issues = [];
60126               var lon = node.loc[0];
60127               var lat = node.loc[1];
60128               var lon_range = geoMetersToLon(pointThresholdMeters, lat) / 2;
60129               var lat_range = geoMetersToLat(pointThresholdMeters) / 2;
60130               var queryExtent = geoExtent([[lon - lon_range, lat - lat_range], [lon + lon_range, lat + lat_range]]);
60131               var intersected = context.history().tree().intersects(queryExtent, graph);
60132
60133               for (var j = 0; j < intersected.length; j++) {
60134                 var nearby = intersected[j];
60135                 if (nearby.id === node.id) continue;
60136                 if (nearby.type !== 'node' || nearby.geometry(graph) !== 'point') continue;
60137
60138                 if (nearby.loc === node.loc || geoSphericalDistance(node.loc, nearby.loc) < pointThresholdMeters) {
60139                   // allow very close points if tags indicate the z-axis might vary
60140                   var zAxisKeys = {
60141                     layer: true,
60142                     level: true,
60143                     'addr:housenumber': true,
60144                     'addr:unit': true
60145                   };
60146                   var zAxisDifferentiates = false;
60147
60148                   for (var key in zAxisKeys) {
60149                     var nodeValue = node.tags[key] || '0';
60150                     var nearbyValue = nearby.tags[key] || '0';
60151
60152                     if (nodeValue !== nearbyValue) {
60153                       zAxisDifferentiates = true;
60154                       break;
60155                     }
60156                   }
60157
60158                   if (zAxisDifferentiates) continue;
60159                   issues.push(new validationIssue({
60160                     type: type,
60161                     subtype: 'detached',
60162                     severity: 'warning',
60163                     message: function message(context) {
60164                       var entity = context.hasEntity(this.entityIds[0]),
60165                           entity2 = context.hasEntity(this.entityIds[1]);
60166                       return entity && entity2 ? _t.html('issues.close_nodes.detached.message', {
60167                         feature: utilDisplayLabel(entity, context.graph()),
60168                         feature2: utilDisplayLabel(entity2, context.graph())
60169                       }) : '';
60170                     },
60171                     reference: showReference,
60172                     entityIds: [node.id, nearby.id],
60173                     dynamicFixes: function dynamicFixes() {
60174                       return [new validationIssueFix({
60175                         icon: 'iD-operation-disconnect',
60176                         title: _t.html('issues.fix.move_points_apart.title')
60177                       }), new validationIssueFix({
60178                         icon: 'iD-icon-layers',
60179                         title: _t.html('issues.fix.use_different_layers_or_levels.title')
60180                       })];
60181                     }
60182                   }));
60183                 }
60184               }
60185
60186               return issues;
60187
60188               function showReference(selection) {
60189                 var referenceText = _t('issues.close_nodes.detached.reference');
60190                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(referenceText);
60191               }
60192             }
60193
60194             function getWayIssueIfAny(node1, node2, way) {
60195               if (node1.id === node2.id || node1.hasInterestingTags() && node2.hasInterestingTags()) {
60196                 return null;
60197               }
60198
60199               if (node1.loc !== node2.loc) {
60200                 var parentWays1 = graph.parentWays(node1);
60201                 var parentWays2 = new Set(graph.parentWays(node2));
60202                 var sharedWays = parentWays1.filter(function (parentWay) {
60203                   return parentWays2.has(parentWay);
60204                 });
60205                 var thresholds = sharedWays.map(function (parentWay) {
60206                   return thresholdMetersForWay(parentWay);
60207                 });
60208                 var threshold = Math.min.apply(Math, _toConsumableArray(thresholds));
60209                 var distance = geoSphericalDistance(node1.loc, node2.loc);
60210                 if (distance > threshold) return null;
60211               }
60212
60213               return new validationIssue({
60214                 type: type,
60215                 subtype: 'vertices',
60216                 severity: 'warning',
60217                 message: function message(context) {
60218                   var entity = context.hasEntity(this.entityIds[0]);
60219                   return entity ? _t.html('issues.close_nodes.message', {
60220                     way: utilDisplayLabel(entity, context.graph())
60221                   }) : '';
60222                 },
60223                 reference: showReference,
60224                 entityIds: [way.id, node1.id, node2.id],
60225                 loc: node1.loc,
60226                 dynamicFixes: function dynamicFixes() {
60227                   return [new validationIssueFix({
60228                     icon: 'iD-icon-plus',
60229                     title: _t.html('issues.fix.merge_points.title'),
60230                     onClick: function onClick(context) {
60231                       var entityIds = this.issue.entityIds;
60232                       var action = actionMergeNodes([entityIds[1], entityIds[2]]);
60233                       context.perform(action, _t('issues.fix.merge_close_vertices.annotation'));
60234                     }
60235                   }), new validationIssueFix({
60236                     icon: 'iD-operation-disconnect',
60237                     title: _t.html('issues.fix.move_points_apart.title')
60238                   })];
60239                 }
60240               });
60241
60242               function showReference(selection) {
60243                 var referenceText = _t('issues.close_nodes.reference');
60244                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(referenceText);
60245               }
60246             }
60247           };
60248
60249           validation.type = type;
60250           return validation;
60251         }
60252
60253         function validationCrossingWays(context) {
60254           var type = 'crossing_ways'; // returns the way or its parent relation, whichever has a useful feature type
60255
60256           function getFeatureWithFeatureTypeTagsForWay(way, graph) {
60257             if (getFeatureType(way, graph) === null) {
60258               // if the way doesn't match a feature type, check its parent relations
60259               var parentRels = graph.parentRelations(way);
60260
60261               for (var i = 0; i < parentRels.length; i++) {
60262                 var rel = parentRels[i];
60263
60264                 if (getFeatureType(rel, graph) !== null) {
60265                   return rel;
60266                 }
60267               }
60268             }
60269
60270             return way;
60271           }
60272
60273           function hasTag(tags, key) {
60274             return tags[key] !== undefined && tags[key] !== 'no';
60275           }
60276
60277           function taggedAsIndoor(tags) {
60278             return hasTag(tags, 'indoor') || hasTag(tags, 'level') || tags.highway === 'corridor';
60279           }
60280
60281           function allowsBridge(featureType) {
60282             return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
60283           }
60284
60285           function allowsTunnel(featureType) {
60286             return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
60287           } // discard
60288
60289
60290           var ignoredBuildings = {
60291             demolished: true,
60292             dismantled: true,
60293             proposed: true,
60294             razed: true
60295           };
60296
60297           function getFeatureType(entity, graph) {
60298             var geometry = entity.geometry(graph);
60299             if (geometry !== 'line' && geometry !== 'area') return null;
60300             var tags = entity.tags;
60301             if (hasTag(tags, 'building') && !ignoredBuildings[tags.building]) return 'building';
60302             if (hasTag(tags, 'highway') && osmRoutableHighwayTagValues[tags.highway]) return 'highway'; // don't check railway or waterway areas
60303
60304             if (geometry !== 'line') return null;
60305             if (hasTag(tags, 'railway') && osmRailwayTrackTagValues[tags.railway]) return 'railway';
60306             if (hasTag(tags, 'waterway') && osmFlowingWaterwayTagValues[tags.waterway]) return 'waterway';
60307             return null;
60308           }
60309
60310           function isLegitCrossing(tags1, featureType1, tags2, featureType2) {
60311             // assume 0 by default
60312             var level1 = tags1.level || '0';
60313             var level2 = tags2.level || '0';
60314
60315             if (taggedAsIndoor(tags1) && taggedAsIndoor(tags2) && level1 !== level2) {
60316               // assume features don't interact if they're indoor on different levels
60317               return true;
60318             } // assume 0 by default; don't use way.layer() since we account for structures here
60319
60320
60321             var layer1 = tags1.layer || '0';
60322             var layer2 = tags2.layer || '0';
60323
60324             if (allowsBridge(featureType1) && allowsBridge(featureType2)) {
60325               if (hasTag(tags1, 'bridge') && !hasTag(tags2, 'bridge')) return true;
60326               if (!hasTag(tags1, 'bridge') && hasTag(tags2, 'bridge')) return true; // crossing bridges must use different layers
60327
60328               if (hasTag(tags1, 'bridge') && hasTag(tags2, 'bridge') && layer1 !== layer2) return true;
60329             } else if (allowsBridge(featureType1) && hasTag(tags1, 'bridge')) return true;else if (allowsBridge(featureType2) && hasTag(tags2, 'bridge')) return true;
60330
60331             if (allowsTunnel(featureType1) && allowsTunnel(featureType2)) {
60332               if (hasTag(tags1, 'tunnel') && !hasTag(tags2, 'tunnel')) return true;
60333               if (!hasTag(tags1, 'tunnel') && hasTag(tags2, 'tunnel')) return true; // crossing tunnels must use different layers
60334
60335               if (hasTag(tags1, 'tunnel') && hasTag(tags2, 'tunnel') && layer1 !== layer2) return true;
60336             } 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
60337
60338
60339             if (featureType1 === 'waterway' && featureType2 === 'highway' && tags2.man_made === 'pier') return true;
60340             if (featureType2 === 'waterway' && featureType1 === 'highway' && tags1.man_made === 'pier') return true;
60341
60342             if (featureType1 === 'building' || featureType2 === 'building') {
60343               // for building crossings, different layers are enough
60344               if (layer1 !== layer2) return true;
60345             }
60346
60347             return false;
60348           } // highway values for which we shouldn't recommend connecting to waterways
60349
60350
60351           var highwaysDisallowingFords = {
60352             motorway: true,
60353             motorway_link: true,
60354             trunk: true,
60355             trunk_link: true,
60356             primary: true,
60357             primary_link: true,
60358             secondary: true,
60359             secondary_link: true
60360           };
60361           var nonCrossingHighways = {
60362             track: true
60363           };
60364
60365           function tagsForConnectionNodeIfAllowed(entity1, entity2, graph) {
60366             var featureType1 = getFeatureType(entity1, graph);
60367             var featureType2 = getFeatureType(entity2, graph);
60368             var geometry1 = entity1.geometry(graph);
60369             var geometry2 = entity2.geometry(graph);
60370             var bothLines = geometry1 === 'line' && geometry2 === 'line';
60371
60372             if (featureType1 === featureType2) {
60373               if (featureType1 === 'highway') {
60374                 var entity1IsPath = osmPathHighwayTagValues[entity1.tags.highway];
60375                 var entity2IsPath = osmPathHighwayTagValues[entity2.tags.highway];
60376
60377                 if ((entity1IsPath || entity2IsPath) && entity1IsPath !== entity2IsPath) {
60378                   // one feature is a path but not both
60379                   var roadFeature = entity1IsPath ? entity2 : entity1;
60380
60381                   if (nonCrossingHighways[roadFeature.tags.highway]) {
60382                     // don't mark path connections with certain roads as crossings
60383                     return {};
60384                   }
60385
60386                   var pathFeature = entity1IsPath ? entity1 : entity2;
60387
60388                   if (['marked', 'unmarked'].indexOf(pathFeature.tags.crossing) !== -1) {
60389                     // if the path is a crossing, match the crossing type
60390                     return bothLines ? {
60391                       highway: 'crossing',
60392                       crossing: pathFeature.tags.crossing
60393                     } : {};
60394                   } // don't add a `crossing` subtag to ambiguous crossings
60395
60396
60397                   return bothLines ? {
60398                     highway: 'crossing'
60399                   } : {};
60400                 }
60401
60402                 return {};
60403               }
60404
60405               if (featureType1 === 'waterway') return {};
60406               if (featureType1 === 'railway') return {};
60407             } else {
60408               var featureTypes = [featureType1, featureType2];
60409
60410               if (featureTypes.indexOf('highway') !== -1) {
60411                 if (featureTypes.indexOf('railway') !== -1) {
60412                   if (!bothLines) return {};
60413                   var isTram = entity1.tags.railway === 'tram' || entity2.tags.railway === 'tram';
60414
60415                   if (osmPathHighwayTagValues[entity1.tags.highway] || osmPathHighwayTagValues[entity2.tags.highway]) {
60416                     // path-tram connections use this tag
60417                     if (isTram) return {
60418                       railway: 'tram_crossing'
60419                     }; // other path-rail connections use this tag
60420
60421                     return {
60422                       railway: 'crossing'
60423                     };
60424                   } else {
60425                     // path-tram connections use this tag
60426                     if (isTram) return {
60427                       railway: 'tram_level_crossing'
60428                     }; // other road-rail connections use this tag
60429
60430                     return {
60431                       railway: 'level_crossing'
60432                     };
60433                   }
60434                 }
60435
60436                 if (featureTypes.indexOf('waterway') !== -1) {
60437                   // do not allow fords on structures
60438                   if (hasTag(entity1.tags, 'tunnel') && hasTag(entity2.tags, 'tunnel')) return null;
60439                   if (hasTag(entity1.tags, 'bridge') && hasTag(entity2.tags, 'bridge')) return null;
60440
60441                   if (highwaysDisallowingFords[entity1.tags.highway] || highwaysDisallowingFords[entity2.tags.highway]) {
60442                     // do not allow fords on major highways
60443                     return null;
60444                   }
60445
60446                   return bothLines ? {
60447                     ford: 'yes'
60448                   } : {};
60449                 }
60450               }
60451             }
60452
60453             return null;
60454           }
60455
60456           function findCrossingsByWay(way1, graph, tree) {
60457             var edgeCrossInfos = [];
60458             if (way1.type !== 'way') return edgeCrossInfos;
60459             var taggedFeature1 = getFeatureWithFeatureTypeTagsForWay(way1, graph);
60460             var way1FeatureType = getFeatureType(taggedFeature1, graph);
60461             if (way1FeatureType === null) return edgeCrossInfos;
60462             var checkedSingleCrossingWays = {}; // declare vars ahead of time to reduce garbage collection
60463
60464             var i, j;
60465             var extent;
60466             var n1, n2, nA, nB, nAId, nBId;
60467             var segment1, segment2;
60468             var oneOnly;
60469             var segmentInfos, segment2Info, way2, taggedFeature2, way2FeatureType;
60470             var way1Nodes = graph.childNodes(way1);
60471             var comparedWays = {};
60472
60473             for (i = 0; i < way1Nodes.length - 1; i++) {
60474               n1 = way1Nodes[i];
60475               n2 = way1Nodes[i + 1];
60476               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
60477               // of overlapping ways
60478
60479               segmentInfos = tree.waySegments(extent, graph);
60480
60481               for (j = 0; j < segmentInfos.length; j++) {
60482                 segment2Info = segmentInfos[j]; // don't check for self-intersection in this validation
60483
60484                 if (segment2Info.wayId === way1.id) continue; // skip if this way was already checked and only one issue is needed
60485
60486                 if (checkedSingleCrossingWays[segment2Info.wayId]) continue; // mark this way as checked even if there are no crossings
60487
60488                 comparedWays[segment2Info.wayId] = true;
60489                 way2 = graph.hasEntity(segment2Info.wayId);
60490                 if (!way2) continue;
60491                 taggedFeature2 = getFeatureWithFeatureTypeTagsForWay(way2, graph); // only check crossing highway, waterway, building, and railway
60492
60493                 way2FeatureType = getFeatureType(taggedFeature2, graph);
60494
60495                 if (way2FeatureType === null || isLegitCrossing(taggedFeature1.tags, way1FeatureType, taggedFeature2.tags, way2FeatureType)) {
60496                   continue;
60497                 } // create only one issue for building crossings
60498
60499
60500                 oneOnly = way1FeatureType === 'building' || way2FeatureType === 'building';
60501                 nAId = segment2Info.nodes[0];
60502                 nBId = segment2Info.nodes[1];
60503
60504                 if (nAId === n1.id || nAId === n2.id || nBId === n1.id || nBId === n2.id) {
60505                   // n1 or n2 is a connection node; skip
60506                   continue;
60507                 }
60508
60509                 nA = graph.hasEntity(nAId);
60510                 if (!nA) continue;
60511                 nB = graph.hasEntity(nBId);
60512                 if (!nB) continue;
60513                 segment1 = [n1.loc, n2.loc];
60514                 segment2 = [nA.loc, nB.loc];
60515                 var point = geoLineIntersection(segment1, segment2);
60516
60517                 if (point) {
60518                   edgeCrossInfos.push({
60519                     wayInfos: [{
60520                       way: way1,
60521                       featureType: way1FeatureType,
60522                       edge: [n1.id, n2.id]
60523                     }, {
60524                       way: way2,
60525                       featureType: way2FeatureType,
60526                       edge: [nA.id, nB.id]
60527                     }],
60528                     crossPoint: point
60529                   });
60530
60531                   if (oneOnly) {
60532                     checkedSingleCrossingWays[way2.id] = true;
60533                     break;
60534                   }
60535                 }
60536               }
60537             }
60538
60539             return edgeCrossInfos;
60540           }
60541
60542           function waysToCheck(entity, graph) {
60543             var featureType = getFeatureType(entity, graph);
60544             if (!featureType) return [];
60545
60546             if (entity.type === 'way') {
60547               return [entity];
60548             } else if (entity.type === 'relation') {
60549               return entity.members.reduce(function (array, member) {
60550                 if (member.type === 'way' && ( // only look at geometry ways
60551                 !member.role || member.role === 'outer' || member.role === 'inner')) {
60552                   var entity = graph.hasEntity(member.id); // don't add duplicates
60553
60554                   if (entity && array.indexOf(entity) === -1) {
60555                     array.push(entity);
60556                   }
60557                 }
60558
60559                 return array;
60560               }, []);
60561             }
60562
60563             return [];
60564           }
60565
60566           var validation = function checkCrossingWays(entity, graph) {
60567             var tree = context.history().tree();
60568             var ways = waysToCheck(entity, graph);
60569             var issues = []; // declare these here to reduce garbage collection
60570
60571             var wayIndex, crossingIndex, crossings;
60572
60573             for (wayIndex in ways) {
60574               crossings = findCrossingsByWay(ways[wayIndex], graph, tree);
60575
60576               for (crossingIndex in crossings) {
60577                 issues.push(createIssue(crossings[crossingIndex], graph));
60578               }
60579             }
60580
60581             return issues;
60582           };
60583
60584           function createIssue(crossing, graph) {
60585             // use the entities with the tags that define the feature type
60586             crossing.wayInfos.sort(function (way1Info, way2Info) {
60587               var type1 = way1Info.featureType;
60588               var type2 = way2Info.featureType;
60589
60590               if (type1 === type2) {
60591                 return utilDisplayLabel(way1Info.way, graph) > utilDisplayLabel(way2Info.way, graph);
60592               } else if (type1 === 'waterway') {
60593                 return true;
60594               } else if (type2 === 'waterway') {
60595                 return false;
60596               }
60597
60598               return type1 < type2;
60599             });
60600             var entities = crossing.wayInfos.map(function (wayInfo) {
60601               return getFeatureWithFeatureTypeTagsForWay(wayInfo.way, graph);
60602             });
60603             var edges = [crossing.wayInfos[0].edge, crossing.wayInfos[1].edge];
60604             var featureTypes = [crossing.wayInfos[0].featureType, crossing.wayInfos[1].featureType];
60605             var connectionTags = tagsForConnectionNodeIfAllowed(entities[0], entities[1], graph);
60606             var featureType1 = crossing.wayInfos[0].featureType;
60607             var featureType2 = crossing.wayInfos[1].featureType;
60608             var isCrossingIndoors = taggedAsIndoor(entities[0].tags) && taggedAsIndoor(entities[1].tags);
60609             var isCrossingTunnels = allowsTunnel(featureType1) && hasTag(entities[0].tags, 'tunnel') && allowsTunnel(featureType2) && hasTag(entities[1].tags, 'tunnel');
60610             var isCrossingBridges = allowsBridge(featureType1) && hasTag(entities[0].tags, 'bridge') && allowsBridge(featureType2) && hasTag(entities[1].tags, 'bridge');
60611             var subtype = [featureType1, featureType2].sort().join('-');
60612             var crossingTypeID = subtype;
60613
60614             if (isCrossingIndoors) {
60615               crossingTypeID = 'indoor-indoor';
60616             } else if (isCrossingTunnels) {
60617               crossingTypeID = 'tunnel-tunnel';
60618             } else if (isCrossingBridges) {
60619               crossingTypeID = 'bridge-bridge';
60620             }
60621
60622             if (connectionTags && (isCrossingIndoors || isCrossingTunnels || isCrossingBridges)) {
60623               crossingTypeID += '_connectable';
60624             }
60625
60626             return new validationIssue({
60627               type: type,
60628               subtype: subtype,
60629               severity: 'warning',
60630               message: function message(context) {
60631                 var graph = context.graph();
60632                 var entity1 = graph.hasEntity(this.entityIds[0]),
60633                     entity2 = graph.hasEntity(this.entityIds[1]);
60634                 return entity1 && entity2 ? _t.html('issues.crossing_ways.message', {
60635                   feature: utilDisplayLabel(entity1, graph),
60636                   feature2: utilDisplayLabel(entity2, graph)
60637                 }) : '';
60638               },
60639               reference: showReference,
60640               entityIds: entities.map(function (entity) {
60641                 return entity.id;
60642               }),
60643               data: {
60644                 edges: edges,
60645                 featureTypes: featureTypes,
60646                 connectionTags: connectionTags
60647               },
60648               // differentiate based on the loc since two ways can cross multiple times
60649               hash: crossing.crossPoint.toString() + // if the edges change then so does the fix
60650               edges.slice().sort(function (edge1, edge2) {
60651                 // order to assure hash is deterministic
60652                 return edge1[0] < edge2[0] ? -1 : 1;
60653               }).toString() + // ensure the correct connection tags are added in the fix
60654               JSON.stringify(connectionTags),
60655               loc: crossing.crossPoint,
60656               dynamicFixes: function dynamicFixes(context) {
60657                 var mode = context.mode();
60658                 if (!mode || mode.id !== 'select' || mode.selectedIDs().length !== 1) return [];
60659                 var selectedIndex = this.entityIds[0] === mode.selectedIDs()[0] ? 0 : 1;
60660                 var selectedFeatureType = this.data.featureTypes[selectedIndex];
60661                 var otherFeatureType = this.data.featureTypes[selectedIndex === 0 ? 1 : 0];
60662                 var fixes = [];
60663
60664                 if (connectionTags) {
60665                   fixes.push(makeConnectWaysFix(this.data.connectionTags));
60666                 }
60667
60668                 if (isCrossingIndoors) {
60669                   fixes.push(new validationIssueFix({
60670                     icon: 'iD-icon-layers',
60671                     title: _t.html('issues.fix.use_different_levels.title')
60672                   }));
60673                 } else if (isCrossingTunnels || isCrossingBridges || featureType1 === 'building' || featureType2 === 'building') {
60674                   fixes.push(makeChangeLayerFix('higher'));
60675                   fixes.push(makeChangeLayerFix('lower')); // can only add bridge/tunnel if both features are lines
60676                 } else if (context.graph().geometry(this.entityIds[0]) === 'line' && context.graph().geometry(this.entityIds[1]) === 'line') {
60677                   // don't recommend adding bridges to waterways since they're uncommon
60678                   if (allowsBridge(selectedFeatureType) && selectedFeatureType !== 'waterway') {
60679                     fixes.push(makeAddBridgeOrTunnelFix('add_a_bridge', 'temaki-bridge', 'bridge'));
60680                   } // don't recommend adding tunnels under waterways since they're uncommon
60681
60682
60683                   var skipTunnelFix = otherFeatureType === 'waterway' && selectedFeatureType !== 'waterway';
60684
60685                   if (allowsTunnel(selectedFeatureType) && !skipTunnelFix) {
60686                     fixes.push(makeAddBridgeOrTunnelFix('add_a_tunnel', 'temaki-tunnel', 'tunnel'));
60687                   }
60688                 } // repositioning the features is always an option
60689
60690
60691                 fixes.push(new validationIssueFix({
60692                   icon: 'iD-operation-move',
60693                   title: _t.html('issues.fix.reposition_features.title')
60694                 }));
60695                 return fixes;
60696               }
60697             });
60698
60699             function showReference(selection) {
60700               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.crossing_ways.' + crossingTypeID + '.reference'));
60701             }
60702           }
60703
60704           function makeAddBridgeOrTunnelFix(fixTitleID, iconName, bridgeOrTunnel) {
60705             return new validationIssueFix({
60706               icon: iconName,
60707               title: _t.html('issues.fix.' + fixTitleID + '.title'),
60708               onClick: function onClick(context) {
60709                 var mode = context.mode();
60710                 if (!mode || mode.id !== 'select') return;
60711                 var selectedIDs = mode.selectedIDs();
60712                 if (selectedIDs.length !== 1) return;
60713                 var selectedWayID = selectedIDs[0];
60714                 if (!context.hasEntity(selectedWayID)) return;
60715                 var resultWayIDs = [selectedWayID];
60716                 var edge, crossedEdge, crossedWayID;
60717
60718                 if (this.issue.entityIds[0] === selectedWayID) {
60719                   edge = this.issue.data.edges[0];
60720                   crossedEdge = this.issue.data.edges[1];
60721                   crossedWayID = this.issue.entityIds[1];
60722                 } else {
60723                   edge = this.issue.data.edges[1];
60724                   crossedEdge = this.issue.data.edges[0];
60725                   crossedWayID = this.issue.entityIds[0];
60726                 }
60727
60728                 var crossingLoc = this.issue.loc;
60729                 var projection = context.projection;
60730
60731                 var action = function actionAddStructure(graph) {
60732                   var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
60733                   var crossedWay = graph.hasEntity(crossedWayID); // use the explicit width of the crossed feature as the structure length, if available
60734
60735                   var structLengthMeters = crossedWay && crossedWay.tags.width && parseFloat(crossedWay.tags.width);
60736
60737                   if (!structLengthMeters) {
60738                     // if no explicit width is set, approximate the width based on the tags
60739                     structLengthMeters = crossedWay && crossedWay.impliedLineWidthMeters();
60740                   }
60741
60742                   if (structLengthMeters) {
60743                     if (getFeatureType(crossedWay, graph) === 'railway') {
60744                       // bridges over railways are generally much longer than the rail bed itself, compensate
60745                       structLengthMeters *= 2;
60746                     }
60747                   } else {
60748                     // should ideally never land here since all rail/water/road tags should have an implied width
60749                     structLengthMeters = 8;
60750                   }
60751
60752                   var a1 = geoAngle(edgeNodes[0], edgeNodes[1], projection) + Math.PI;
60753                   var a2 = geoAngle(graph.entity(crossedEdge[0]), graph.entity(crossedEdge[1]), projection) + Math.PI;
60754                   var crossingAngle = Math.max(a1, a2) - Math.min(a1, a2);
60755                   if (crossingAngle > Math.PI) crossingAngle -= Math.PI; // lengthen the structure to account for the angle of the crossing
60756
60757                   structLengthMeters = structLengthMeters / 2 / Math.sin(crossingAngle) * 2; // add padding since the structure must extend past the edges of the crossed feature
60758
60759                   structLengthMeters += 4; // clamp the length to a reasonable range
60760
60761                   structLengthMeters = Math.min(Math.max(structLengthMeters, 4), 50);
60762
60763                   function geomToProj(geoPoint) {
60764                     return [geoLonToMeters(geoPoint[0], geoPoint[1]), geoLatToMeters(geoPoint[1])];
60765                   }
60766
60767                   function projToGeom(projPoint) {
60768                     var lat = geoMetersToLat(projPoint[1]);
60769                     return [geoMetersToLon(projPoint[0], lat), lat];
60770                   }
60771
60772                   var projEdgeNode1 = geomToProj(edgeNodes[0].loc);
60773                   var projEdgeNode2 = geomToProj(edgeNodes[1].loc);
60774                   var projectedAngle = geoVecAngle(projEdgeNode1, projEdgeNode2);
60775                   var projectedCrossingLoc = geomToProj(crossingLoc);
60776                   var linearToSphericalMetersRatio = geoVecLength(projEdgeNode1, projEdgeNode2) / geoSphericalDistance(edgeNodes[0].loc, edgeNodes[1].loc);
60777
60778                   function locSphericalDistanceFromCrossingLoc(angle, distanceMeters) {
60779                     var lengthSphericalMeters = distanceMeters * linearToSphericalMetersRatio;
60780                     return projToGeom([projectedCrossingLoc[0] + Math.cos(angle) * lengthSphericalMeters, projectedCrossingLoc[1] + Math.sin(angle) * lengthSphericalMeters]);
60781                   }
60782
60783                   var endpointLocGetter1 = function endpointLocGetter1(lengthMeters) {
60784                     return locSphericalDistanceFromCrossingLoc(projectedAngle, lengthMeters);
60785                   };
60786
60787                   var endpointLocGetter2 = function endpointLocGetter2(lengthMeters) {
60788                     return locSphericalDistanceFromCrossingLoc(projectedAngle + Math.PI, lengthMeters);
60789                   }; // avoid creating very short edges from splitting too close to another node
60790
60791
60792                   var minEdgeLengthMeters = 0.55; // decide where to bound the structure along the way, splitting as necessary
60793
60794                   function determineEndpoint(edge, endNode, locGetter) {
60795                     var newNode;
60796                     var idealLengthMeters = structLengthMeters / 2; // distance between the crossing location and the end of the edge,
60797                     // the maximum length of this side of the structure
60798
60799                     var crossingToEdgeEndDistance = geoSphericalDistance(crossingLoc, endNode.loc);
60800
60801                     if (crossingToEdgeEndDistance - idealLengthMeters > minEdgeLengthMeters) {
60802                       // the edge is long enough to insert a new node
60803                       // the loc that would result in the full expected length
60804                       var idealNodeLoc = locGetter(idealLengthMeters);
60805                       newNode = osmNode();
60806                       graph = actionAddMidpoint({
60807                         loc: idealNodeLoc,
60808                         edge: edge
60809                       }, newNode)(graph);
60810                     } else {
60811                       var edgeCount = 0;
60812                       endNode.parentIntersectionWays(graph).forEach(function (way) {
60813                         way.nodes.forEach(function (nodeID) {
60814                           if (nodeID === endNode.id) {
60815                             if (endNode.id === way.first() && endNode.id !== way.last() || endNode.id === way.last() && endNode.id !== way.first()) {
60816                               edgeCount += 1;
60817                             } else {
60818                               edgeCount += 2;
60819                             }
60820                           }
60821                         });
60822                       });
60823
60824                       if (edgeCount >= 3) {
60825                         // the end node is a junction, try to leave a segment
60826                         // between it and the structure - #7202
60827                         var insetLength = crossingToEdgeEndDistance - minEdgeLengthMeters;
60828
60829                         if (insetLength > minEdgeLengthMeters) {
60830                           var insetNodeLoc = locGetter(insetLength);
60831                           newNode = osmNode();
60832                           graph = actionAddMidpoint({
60833                             loc: insetNodeLoc,
60834                             edge: edge
60835                           }, newNode)(graph);
60836                         }
60837                       }
60838                     } // if the edge is too short to subdivide as desired, then
60839                     // just bound the structure at the existing end node
60840
60841
60842                     if (!newNode) newNode = endNode;
60843                     var splitAction = actionSplit([newNode.id]).limitWays(resultWayIDs); // only split selected or created ways
60844                     // do the split
60845
60846                     graph = splitAction(graph);
60847
60848                     if (splitAction.getCreatedWayIDs().length) {
60849                       resultWayIDs.push(splitAction.getCreatedWayIDs()[0]);
60850                     }
60851
60852                     return newNode;
60853                   }
60854
60855                   var structEndNode1 = determineEndpoint(edge, edgeNodes[1], endpointLocGetter1);
60856                   var structEndNode2 = determineEndpoint([edgeNodes[0].id, structEndNode1.id], edgeNodes[0], endpointLocGetter2);
60857                   var structureWay = resultWayIDs.map(function (id) {
60858                     return graph.entity(id);
60859                   }).find(function (way) {
60860                     return way.nodes.indexOf(structEndNode1.id) !== -1 && way.nodes.indexOf(structEndNode2.id) !== -1;
60861                   });
60862                   var tags = Object.assign({}, structureWay.tags); // copy tags
60863
60864                   if (bridgeOrTunnel === 'bridge') {
60865                     tags.bridge = 'yes';
60866                     tags.layer = '1';
60867                   } else {
60868                     var tunnelValue = 'yes';
60869
60870                     if (getFeatureType(structureWay, graph) === 'waterway') {
60871                       // use `tunnel=culvert` for waterways by default
60872                       tunnelValue = 'culvert';
60873                     }
60874
60875                     tags.tunnel = tunnelValue;
60876                     tags.layer = '-1';
60877                   } // apply the structure tags to the way
60878
60879
60880                   graph = actionChangeTags(structureWay.id, tags)(graph);
60881                   return graph;
60882                 };
60883
60884                 context.perform(action, _t('issues.fix.' + fixTitleID + '.annotation'));
60885                 context.enter(modeSelect(context, resultWayIDs));
60886               }
60887             });
60888           }
60889
60890           function makeConnectWaysFix(connectionTags) {
60891             var fixTitleID = 'connect_features';
60892
60893             if (connectionTags.ford) {
60894               fixTitleID = 'connect_using_ford';
60895             }
60896
60897             return new validationIssueFix({
60898               icon: 'iD-icon-crossing',
60899               title: _t.html('issues.fix.' + fixTitleID + '.title'),
60900               onClick: function onClick(context) {
60901                 var loc = this.issue.loc;
60902                 var connectionTags = this.issue.data.connectionTags;
60903                 var edges = this.issue.data.edges;
60904                 context.perform(function actionConnectCrossingWays(graph) {
60905                   // create the new node for the points
60906                   var node = osmNode({
60907                     loc: loc,
60908                     tags: connectionTags
60909                   });
60910                   graph = graph.replace(node);
60911                   var nodesToMerge = [node.id];
60912                   var mergeThresholdInMeters = 0.75;
60913                   edges.forEach(function (edge) {
60914                     var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
60915                     var closestNodeInfo = geoSphericalClosestNode(edgeNodes, loc); // if there is already a point nearby, use that
60916
60917                     if (closestNodeInfo.distance < mergeThresholdInMeters) {
60918                       nodesToMerge.push(closestNodeInfo.node.id); // else add the new node to the way
60919                     } else {
60920                       graph = actionAddMidpoint({
60921                         loc: loc,
60922                         edge: edge
60923                       }, node)(graph);
60924                     }
60925                   });
60926
60927                   if (nodesToMerge.length > 1) {
60928                     // if we're using nearby nodes, merge them with the new node
60929                     graph = actionMergeNodes(nodesToMerge, loc)(graph);
60930                   }
60931
60932                   return graph;
60933                 }, _t('issues.fix.connect_crossing_features.annotation'));
60934               }
60935             });
60936           }
60937
60938           function makeChangeLayerFix(higherOrLower) {
60939             return new validationIssueFix({
60940               icon: 'iD-icon-' + (higherOrLower === 'higher' ? 'up' : 'down'),
60941               title: _t.html('issues.fix.tag_this_as_' + higherOrLower + '.title'),
60942               onClick: function onClick(context) {
60943                 var mode = context.mode();
60944                 if (!mode || mode.id !== 'select') return;
60945                 var selectedIDs = mode.selectedIDs();
60946                 if (selectedIDs.length !== 1) return;
60947                 var selectedID = selectedIDs[0];
60948                 if (!this.issue.entityIds.some(function (entityId) {
60949                   return entityId === selectedID;
60950                 })) return;
60951                 var entity = context.hasEntity(selectedID);
60952                 if (!entity) return;
60953                 var tags = Object.assign({}, entity.tags); // shallow copy
60954
60955                 var layer = tags.layer && Number(tags.layer);
60956
60957                 if (layer && !isNaN(layer)) {
60958                   if (higherOrLower === 'higher') {
60959                     layer += 1;
60960                   } else {
60961                     layer -= 1;
60962                   }
60963                 } else {
60964                   if (higherOrLower === 'higher') {
60965                     layer = 1;
60966                   } else {
60967                     layer = -1;
60968                   }
60969                 }
60970
60971                 tags.layer = layer.toString();
60972                 context.perform(actionChangeTags(entity.id, tags), _t('operations.change_tags.annotation'));
60973               }
60974             });
60975           }
60976
60977           validation.type = type;
60978           return validation;
60979         }
60980
60981         function validationDisconnectedWay() {
60982           var type = 'disconnected_way';
60983
60984           function isTaggedAsHighway(entity) {
60985             return osmRoutableHighwayTagValues[entity.tags.highway];
60986           }
60987
60988           var validation = function checkDisconnectedWay(entity, graph) {
60989             var routingIslandWays = routingIslandForEntity(entity);
60990             if (!routingIslandWays) return [];
60991             return [new validationIssue({
60992               type: type,
60993               subtype: 'highway',
60994               severity: 'warning',
60995               message: function message(context) {
60996                 var entity = this.entityIds.length && context.hasEntity(this.entityIds[0]);
60997                 var label = entity && utilDisplayLabel(entity, context.graph());
60998                 return _t.html('issues.disconnected_way.routable.message', {
60999                   count: this.entityIds.length,
61000                   highway: label
61001                 });
61002               },
61003               reference: showReference,
61004               entityIds: Array.from(routingIslandWays).map(function (way) {
61005                 return way.id;
61006               }),
61007               dynamicFixes: makeFixes
61008             })];
61009
61010             function makeFixes(context) {
61011               var fixes = [];
61012               var singleEntity = this.entityIds.length === 1 && context.hasEntity(this.entityIds[0]);
61013
61014               if (singleEntity) {
61015                 if (singleEntity.type === 'way' && !singleEntity.isClosed()) {
61016                   var textDirection = _mainLocalizer.textDirection();
61017                   var startFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.first(), 'start');
61018                   if (startFix) fixes.push(startFix);
61019                   var endFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.last(), 'end');
61020                   if (endFix) fixes.push(endFix);
61021                 }
61022
61023                 if (!fixes.length) {
61024                   fixes.push(new validationIssueFix({
61025                     title: _t.html('issues.fix.connect_feature.title')
61026                   }));
61027                 }
61028
61029                 fixes.push(new validationIssueFix({
61030                   icon: 'iD-operation-delete',
61031                   title: _t.html('issues.fix.delete_feature.title'),
61032                   entityIds: [singleEntity.id],
61033                   onClick: function onClick(context) {
61034                     var id = this.issue.entityIds[0];
61035                     var operation = operationDelete(context, [id]);
61036
61037                     if (!operation.disabled()) {
61038                       operation();
61039                     }
61040                   }
61041                 }));
61042               } else {
61043                 fixes.push(new validationIssueFix({
61044                   title: _t.html('issues.fix.connect_features.title')
61045                 }));
61046               }
61047
61048               return fixes;
61049             }
61050
61051             function showReference(selection) {
61052               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.disconnected_way.routable.reference'));
61053             }
61054
61055             function routingIslandForEntity(entity) {
61056               var routingIsland = new Set(); // the interconnected routable features
61057
61058               var waysToCheck = []; // the queue of remaining routable ways to traverse
61059
61060               function queueParentWays(node) {
61061                 graph.parentWays(node).forEach(function (parentWay) {
61062                   if (!routingIsland.has(parentWay) && // only check each feature once
61063                   isRoutableWay(parentWay, false)) {
61064                     // only check routable features
61065                     routingIsland.add(parentWay);
61066                     waysToCheck.push(parentWay);
61067                   }
61068                 });
61069               }
61070
61071               if (entity.type === 'way' && isRoutableWay(entity, true)) {
61072                 routingIsland.add(entity);
61073                 waysToCheck.push(entity);
61074               } else if (entity.type === 'node' && isRoutableNode(entity)) {
61075                 routingIsland.add(entity);
61076                 queueParentWays(entity);
61077               } else {
61078                 // this feature isn't routable, cannot be a routing island
61079                 return null;
61080               }
61081
61082               while (waysToCheck.length) {
61083                 var wayToCheck = waysToCheck.pop();
61084                 var childNodes = graph.childNodes(wayToCheck);
61085
61086                 for (var i in childNodes) {
61087                   var vertex = childNodes[i];
61088
61089                   if (isConnectedVertex(vertex)) {
61090                     // found a link to the wider network, not a routing island
61091                     return null;
61092                   }
61093
61094                   if (isRoutableNode(vertex)) {
61095                     routingIsland.add(vertex);
61096                   }
61097
61098                   queueParentWays(vertex);
61099                 }
61100               } // no network link found, this is a routing island, return its members
61101
61102
61103               return routingIsland;
61104             }
61105
61106             function isConnectedVertex(vertex) {
61107               // assume ways overlapping unloaded tiles are connected to the wider road network  - #5938
61108               var osm = services.osm;
61109               if (osm && !osm.isDataLoaded(vertex.loc)) return true; // entrances are considered connected
61110
61111               if (vertex.tags.entrance && vertex.tags.entrance !== 'no') return true;
61112               if (vertex.tags.amenity === 'parking_entrance') return true;
61113               return false;
61114             }
61115
61116             function isRoutableNode(node) {
61117               // treat elevators as distinct features in the highway network
61118               if (node.tags.highway === 'elevator') return true;
61119               return false;
61120             }
61121
61122             function isRoutableWay(way, ignoreInnerWays) {
61123               if (isTaggedAsHighway(way) || way.tags.route === 'ferry') return true;
61124               return graph.parentRelations(way).some(function (parentRelation) {
61125                 if (parentRelation.tags.type === 'route' && parentRelation.tags.route === 'ferry') return true;
61126                 if (parentRelation.isMultipolygon() && isTaggedAsHighway(parentRelation) && (!ignoreInnerWays || parentRelation.memberById(way.id).role !== 'inner')) return true;
61127                 return false;
61128               });
61129             }
61130
61131             function makeContinueDrawingFixIfAllowed(textDirection, vertexID, whichEnd) {
61132               var vertex = graph.hasEntity(vertexID);
61133               if (!vertex || vertex.tags.noexit === 'yes') return null;
61134               var useLeftContinue = whichEnd === 'start' && textDirection === 'ltr' || whichEnd === 'end' && textDirection === 'rtl';
61135               return new validationIssueFix({
61136                 icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''),
61137                 title: _t.html('issues.fix.continue_from_' + whichEnd + '.title'),
61138                 entityIds: [vertexID],
61139                 onClick: function onClick(context) {
61140                   var wayId = this.issue.entityIds[0];
61141                   var way = context.hasEntity(wayId);
61142                   var vertexId = this.entityIds[0];
61143                   var vertex = context.hasEntity(vertexId);
61144                   if (!way || !vertex) return; // make sure the vertex is actually visible and editable
61145
61146                   var map = context.map();
61147
61148                   if (!context.editable() || !map.trimmedExtent().contains(vertex.loc)) {
61149                     map.zoomToEase(vertex);
61150                   }
61151
61152                   context.enter(modeDrawLine(context, wayId, context.graph(), 'line', way.affix(vertexId), true));
61153                 }
61154               });
61155             }
61156           };
61157
61158           validation.type = type;
61159           return validation;
61160         }
61161
61162         function validationFormatting() {
61163           var type = 'invalid_format';
61164
61165           var validation = function validation(entity) {
61166             var issues = [];
61167
61168             function isValidEmail(email) {
61169               // Emails in OSM are going to be official so they should be pretty simple
61170               // Using negated lists to better support all possible unicode characters (#6494)
61171               var valid_email = /^[^\(\)\\,":;<>@\[\]]+@[^\(\)\\,":;<>@\[\]\.]+(?:\.[a-z0-9-]+)*$/i; // An empty value is also acceptable
61172
61173               return !email || valid_email.test(email);
61174             }
61175             /*
61176             function isSchemePresent(url) {
61177                 var valid_scheme = /^https?:\/\//i;
61178                 return (!url || valid_scheme.test(url));
61179             }
61180             */
61181
61182
61183             function showReferenceEmail(selection) {
61184               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.invalid_format.email.reference'));
61185             }
61186             /*
61187             function showReferenceWebsite(selection) {
61188                 selection.selectAll('.issue-reference')
61189                     .data([0])
61190                     .enter()
61191                     .append('div')
61192                     .attr('class', 'issue-reference')
61193                     .html(t.html('issues.invalid_format.website.reference'));
61194             }
61195              if (entity.tags.website) {
61196                 // Multiple websites are possible
61197                 // If ever we support ES6, arrow functions make this nicer
61198                 var websites = entity.tags.website
61199                     .split(';')
61200                     .map(function(s) { return s.trim(); })
61201                     .filter(function(x) { return !isSchemePresent(x); });
61202                  if (websites.length) {
61203                     issues.push(new validationIssue({
61204                         type: type,
61205                         subtype: 'website',
61206                         severity: 'warning',
61207                         message: function(context) {
61208                             var entity = context.hasEntity(this.entityIds[0]);
61209                             return entity ? t.html('issues.invalid_format.website.message' + this.data,
61210                                 { feature: utilDisplayLabel(entity, context.graph()), site: websites.join(', ') }) : '';
61211                         },
61212                         reference: showReferenceWebsite,
61213                         entityIds: [entity.id],
61214                         hash: websites.join(),
61215                         data: (websites.length > 1) ? '_multi' : ''
61216                     }));
61217                 }
61218             }
61219             */
61220
61221
61222             if (entity.tags.email) {
61223               // Multiple emails are possible
61224               var emails = entity.tags.email.split(';').map(function (s) {
61225                 return s.trim();
61226               }).filter(function (x) {
61227                 return !isValidEmail(x);
61228               });
61229
61230               if (emails.length) {
61231                 issues.push(new validationIssue({
61232                   type: type,
61233                   subtype: 'email',
61234                   severity: 'warning',
61235                   message: function message(context) {
61236                     var entity = context.hasEntity(this.entityIds[0]);
61237                     return entity ? _t.html('issues.invalid_format.email.message' + this.data, {
61238                       feature: utilDisplayLabel(entity, context.graph()),
61239                       email: emails.join(', ')
61240                     }) : '';
61241                   },
61242                   reference: showReferenceEmail,
61243                   entityIds: [entity.id],
61244                   hash: emails.join(),
61245                   data: emails.length > 1 ? '_multi' : ''
61246                 }));
61247               }
61248             }
61249
61250             return issues;
61251           };
61252
61253           validation.type = type;
61254           return validation;
61255         }
61256
61257         function validationHelpRequest(context) {
61258           var type = 'help_request';
61259
61260           var validation = function checkFixmeTag(entity) {
61261             if (!entity.tags.fixme) return []; // don't flag fixmes on features added by the user
61262
61263             if (entity.version === undefined) return [];
61264
61265             if (entity.v !== undefined) {
61266               var baseEntity = context.history().base().hasEntity(entity.id); // don't flag fixmes added by the user on existing features
61267
61268               if (!baseEntity || !baseEntity.tags.fixme) return [];
61269             }
61270
61271             return [new validationIssue({
61272               type: type,
61273               subtype: 'fixme_tag',
61274               severity: 'warning',
61275               message: function message(context) {
61276                 var entity = context.hasEntity(this.entityIds[0]);
61277                 return entity ? _t.html('issues.fixme_tag.message', {
61278                   feature: utilDisplayLabel(entity, context.graph())
61279                 }) : '';
61280               },
61281               dynamicFixes: function dynamicFixes() {
61282                 return [new validationIssueFix({
61283                   title: _t.html('issues.fix.address_the_concern.title')
61284                 })];
61285               },
61286               reference: showReference,
61287               entityIds: [entity.id]
61288             })];
61289
61290             function showReference(selection) {
61291               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.fixme_tag.reference'));
61292             }
61293           };
61294
61295           validation.type = type;
61296           return validation;
61297         }
61298
61299         function validationImpossibleOneway() {
61300           var type = 'impossible_oneway';
61301
61302           var validation = function checkImpossibleOneway(entity, graph) {
61303             if (entity.type !== 'way' || entity.geometry(graph) !== 'line') return [];
61304             if (entity.isClosed()) return [];
61305             if (!typeForWay(entity)) return [];
61306             if (!isOneway(entity)) return [];
61307             var firstIssues = issuesForNode(entity, entity.first());
61308             var lastIssues = issuesForNode(entity, entity.last());
61309             return firstIssues.concat(lastIssues);
61310
61311             function typeForWay(way) {
61312               if (way.geometry(graph) !== 'line') return null;
61313               if (osmRoutableHighwayTagValues[way.tags.highway]) return 'highway';
61314               if (osmFlowingWaterwayTagValues[way.tags.waterway]) return 'waterway';
61315               return null;
61316             }
61317
61318             function isOneway(way) {
61319               if (way.tags.oneway === 'yes') return true;
61320               if (way.tags.oneway) return false;
61321
61322               for (var key in way.tags) {
61323                 if (osmOneWayTags[key] && osmOneWayTags[key][way.tags[key]]) {
61324                   return true;
61325                 }
61326               }
61327
61328               return false;
61329             }
61330
61331             function nodeOccursMoreThanOnce(way, nodeID) {
61332               var occurrences = 0;
61333
61334               for (var index in way.nodes) {
61335                 if (way.nodes[index] === nodeID) {
61336                   occurrences += 1;
61337                   if (occurrences > 1) return true;
61338                 }
61339               }
61340
61341               return false;
61342             }
61343
61344             function isConnectedViaOtherTypes(way, node) {
61345               var wayType = typeForWay(way);
61346
61347               if (wayType === 'highway') {
61348                 // entrances are considered connected
61349                 if (node.tags.entrance && node.tags.entrance !== 'no') return true;
61350                 if (node.tags.amenity === 'parking_entrance') return true;
61351               } else if (wayType === 'waterway') {
61352                 if (node.id === way.first()) {
61353                   // multiple waterways may start at the same spring
61354                   if (node.tags.natural === 'spring') return true;
61355                 } else {
61356                   // multiple waterways may end at the same drain
61357                   if (node.tags.manhole === 'drain') return true;
61358                 }
61359               }
61360
61361               return graph.parentWays(node).some(function (parentWay) {
61362                 if (parentWay.id === way.id) return false;
61363
61364                 if (wayType === 'highway') {
61365                   // allow connections to highway areas
61366                   if (parentWay.geometry(graph) === 'area' && osmRoutableHighwayTagValues[parentWay.tags.highway]) return true; // count connections to ferry routes as connected
61367
61368                   if (parentWay.tags.route === 'ferry') return true;
61369                   return graph.parentRelations(parentWay).some(function (parentRelation) {
61370                     if (parentRelation.tags.type === 'route' && parentRelation.tags.route === 'ferry') return true; // allow connections to highway multipolygons
61371
61372                     return parentRelation.isMultipolygon() && osmRoutableHighwayTagValues[parentRelation.tags.highway];
61373                   });
61374                 } else if (wayType === 'waterway') {
61375                   // multiple waterways may start or end at a water body at the same node
61376                   if (parentWay.tags.natural === 'water' || parentWay.tags.natural === 'coastline') return true;
61377                 }
61378
61379                 return false;
61380               });
61381             }
61382
61383             function issuesForNode(way, nodeID) {
61384               var isFirst = nodeID === way.first();
61385               var wayType = typeForWay(way); // ignore if this way is self-connected at this node
61386
61387               if (nodeOccursMoreThanOnce(way, nodeID)) return [];
61388               var osm = services.osm;
61389               if (!osm) return [];
61390               var node = graph.hasEntity(nodeID); // ignore if this node or its tile are unloaded
61391
61392               if (!node || !osm.isDataLoaded(node.loc)) return [];
61393               if (isConnectedViaOtherTypes(way, node)) return [];
61394               var attachedWaysOfSameType = graph.parentWays(node).filter(function (parentWay) {
61395                 if (parentWay.id === way.id) return false;
61396                 return typeForWay(parentWay) === wayType;
61397               }); // assume it's okay for waterways to start or end disconnected for now
61398
61399               if (wayType === 'waterway' && attachedWaysOfSameType.length === 0) return [];
61400               var attachedOneways = attachedWaysOfSameType.filter(function (attachedWay) {
61401                 return isOneway(attachedWay);
61402               }); // ignore if the way is connected to some non-oneway features
61403
61404               if (attachedOneways.length < attachedWaysOfSameType.length) return [];
61405
61406               if (attachedOneways.length) {
61407                 var connectedEndpointsOkay = attachedOneways.some(function (attachedOneway) {
61408                   if ((isFirst ? attachedOneway.first() : attachedOneway.last()) !== nodeID) return true;
61409                   if (nodeOccursMoreThanOnce(attachedOneway, nodeID)) return true;
61410                   return false;
61411                 });
61412                 if (connectedEndpointsOkay) return [];
61413               }
61414
61415               var placement = isFirst ? 'start' : 'end',
61416                   messageID = wayType + '.',
61417                   referenceID = wayType + '.';
61418
61419               if (wayType === 'waterway') {
61420                 messageID += 'connected.' + placement;
61421                 referenceID += 'connected';
61422               } else {
61423                 messageID += placement;
61424                 referenceID += placement;
61425               }
61426
61427               return [new validationIssue({
61428                 type: type,
61429                 subtype: wayType,
61430                 severity: 'warning',
61431                 message: function message(context) {
61432                   var entity = context.hasEntity(this.entityIds[0]);
61433                   return entity ? _t.html('issues.impossible_oneway.' + messageID + '.message', {
61434                     feature: utilDisplayLabel(entity, context.graph())
61435                   }) : '';
61436                 },
61437                 reference: getReference(referenceID),
61438                 entityIds: [way.id, node.id],
61439                 dynamicFixes: function dynamicFixes() {
61440                   var fixes = [];
61441
61442                   if (attachedOneways.length) {
61443                     fixes.push(new validationIssueFix({
61444                       icon: 'iD-operation-reverse',
61445                       title: _t.html('issues.fix.reverse_feature.title'),
61446                       entityIds: [way.id],
61447                       onClick: function onClick(context) {
61448                         var id = this.issue.entityIds[0];
61449                         context.perform(actionReverse(id), _t('operations.reverse.annotation.line', {
61450                           n: 1
61451                         }));
61452                       }
61453                     }));
61454                   }
61455
61456                   if (node.tags.noexit !== 'yes') {
61457                     var textDirection = _mainLocalizer.textDirection();
61458                     var useLeftContinue = isFirst && textDirection === 'ltr' || !isFirst && textDirection === 'rtl';
61459                     fixes.push(new validationIssueFix({
61460                       icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''),
61461                       title: _t.html('issues.fix.continue_from_' + (isFirst ? 'start' : 'end') + '.title'),
61462                       onClick: function onClick(context) {
61463                         var entityID = this.issue.entityIds[0];
61464                         var vertexID = this.issue.entityIds[1];
61465                         var way = context.entity(entityID);
61466                         var vertex = context.entity(vertexID);
61467                         continueDrawing(way, vertex, context);
61468                       }
61469                     }));
61470                   }
61471
61472                   return fixes;
61473                 },
61474                 loc: node.loc
61475               })];
61476
61477               function getReference(referenceID) {
61478                 return function showReference(selection) {
61479                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.impossible_oneway.' + referenceID + '.reference'));
61480                 };
61481               }
61482             }
61483           };
61484
61485           function continueDrawing(way, vertex, context) {
61486             // make sure the vertex is actually visible and editable
61487             var map = context.map();
61488
61489             if (!context.editable() || !map.trimmedExtent().contains(vertex.loc)) {
61490               map.zoomToEase(vertex);
61491             }
61492
61493             context.enter(modeDrawLine(context, way.id, context.graph(), 'line', way.affix(vertex.id), true));
61494           }
61495
61496           validation.type = type;
61497           return validation;
61498         }
61499
61500         function validationIncompatibleSource() {
61501           var type = 'incompatible_source';
61502           var invalidSources = [{
61503             id: 'google',
61504             regex: 'google',
61505             exceptRegex: 'books.google|Google Books|drive.google|googledrive|Google Drive'
61506           }];
61507
61508           var validation = function checkIncompatibleSource(entity) {
61509             var entitySources = entity.tags && entity.tags.source && entity.tags.source.split(';');
61510             if (!entitySources) return [];
61511             var issues = [];
61512             invalidSources.forEach(function (invalidSource) {
61513               var hasInvalidSource = entitySources.some(function (source) {
61514                 if (!source.match(new RegExp(invalidSource.regex, 'i'))) return false;
61515                 if (invalidSource.exceptRegex && source.match(new RegExp(invalidSource.exceptRegex, 'i'))) return false;
61516                 return true;
61517               });
61518               if (!hasInvalidSource) return;
61519               issues.push(new validationIssue({
61520                 type: type,
61521                 severity: 'warning',
61522                 message: function message(context) {
61523                   var entity = context.hasEntity(this.entityIds[0]);
61524                   return entity ? _t.html('issues.incompatible_source.' + invalidSource.id + '.feature.message', {
61525                     feature: utilDisplayLabel(entity, context.graph())
61526                   }) : '';
61527                 },
61528                 reference: getReference(invalidSource.id),
61529                 entityIds: [entity.id],
61530                 dynamicFixes: function dynamicFixes() {
61531                   return [new validationIssueFix({
61532                     title: _t.html('issues.fix.remove_proprietary_data.title')
61533                   })];
61534                 }
61535               }));
61536             });
61537             return issues;
61538
61539             function getReference(id) {
61540               return function showReference(selection) {
61541                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.incompatible_source.' + id + '.reference'));
61542               };
61543             }
61544           };
61545
61546           validation.type = type;
61547           return validation;
61548         }
61549
61550         function validationMaprules() {
61551           var type = 'maprules';
61552
61553           var validation = function checkMaprules(entity, graph) {
61554             if (!services.maprules) return [];
61555             var rules = services.maprules.validationRules();
61556             var issues = [];
61557
61558             for (var i = 0; i < rules.length; i++) {
61559               var rule = rules[i];
61560               rule.findIssues(entity, graph, issues);
61561             }
61562
61563             return issues;
61564           };
61565
61566           validation.type = type;
61567           return validation;
61568         }
61569
61570         function validationMismatchedGeometry() {
61571           var type = 'mismatched_geometry';
61572
61573           function tagSuggestingLineIsArea(entity) {
61574             if (entity.type !== 'way' || entity.isClosed()) return null;
61575             var tagSuggestingArea = entity.tagSuggestingArea();
61576
61577             if (!tagSuggestingArea) {
61578               return null;
61579             }
61580
61581             var asLine = _mainPresetIndex.matchTags(tagSuggestingArea, 'line');
61582             var asArea = _mainPresetIndex.matchTags(tagSuggestingArea, 'area');
61583
61584             if (asLine && asArea && asLine === asArea) {
61585               // these tags also allow lines and making this an area wouldn't matter
61586               return null;
61587             }
61588
61589             return tagSuggestingArea;
61590           }
61591
61592           function makeConnectEndpointsFixOnClick(way, graph) {
61593             // must have at least three nodes to close this automatically
61594             if (way.nodes.length < 3) return null;
61595             var nodes = graph.childNodes(way),
61596                 testNodes;
61597             var firstToLastDistanceMeters = geoSphericalDistance(nodes[0].loc, nodes[nodes.length - 1].loc); // if the distance is very small, attempt to merge the endpoints
61598
61599             if (firstToLastDistanceMeters < 0.75) {
61600               testNodes = nodes.slice(); // shallow copy
61601
61602               testNodes.pop();
61603               testNodes.push(testNodes[0]); // make sure this will not create a self-intersection
61604
61605               if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
61606                 return function (context) {
61607                   var way = context.entity(this.issue.entityIds[0]);
61608                   context.perform(actionMergeNodes([way.nodes[0], way.nodes[way.nodes.length - 1]], nodes[0].loc), _t('issues.fix.connect_endpoints.annotation'));
61609                 };
61610               }
61611             } // if the points were not merged, attempt to close the way
61612
61613
61614             testNodes = nodes.slice(); // shallow copy
61615
61616             testNodes.push(testNodes[0]); // make sure this will not create a self-intersection
61617
61618             if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
61619               return function (context) {
61620                 var wayId = this.issue.entityIds[0];
61621                 var way = context.entity(wayId);
61622                 var nodeId = way.nodes[0];
61623                 var index = way.nodes.length;
61624                 context.perform(actionAddVertex(wayId, nodeId, index), _t('issues.fix.connect_endpoints.annotation'));
61625               };
61626             }
61627           }
61628
61629           function lineTaggedAsAreaIssue(entity) {
61630             var tagSuggestingArea = tagSuggestingLineIsArea(entity);
61631             if (!tagSuggestingArea) return null;
61632             return new validationIssue({
61633               type: type,
61634               subtype: 'area_as_line',
61635               severity: 'warning',
61636               message: function message(context) {
61637                 var entity = context.hasEntity(this.entityIds[0]);
61638                 return entity ? _t.html('issues.tag_suggests_area.message', {
61639                   feature: utilDisplayLabel(entity, 'area'),
61640                   tag: utilTagText({
61641                     tags: tagSuggestingArea
61642                   })
61643                 }) : '';
61644               },
61645               reference: showReference,
61646               entityIds: [entity.id],
61647               hash: JSON.stringify(tagSuggestingArea),
61648               dynamicFixes: function dynamicFixes(context) {
61649                 var fixes = [];
61650                 var entity = context.entity(this.entityIds[0]);
61651                 var connectEndsOnClick = makeConnectEndpointsFixOnClick(entity, context.graph());
61652                 fixes.push(new validationIssueFix({
61653                   title: _t.html('issues.fix.connect_endpoints.title'),
61654                   onClick: connectEndsOnClick
61655                 }));
61656                 fixes.push(new validationIssueFix({
61657                   icon: 'iD-operation-delete',
61658                   title: _t.html('issues.fix.remove_tag.title'),
61659                   onClick: function onClick(context) {
61660                     var entityId = this.issue.entityIds[0];
61661                     var entity = context.entity(entityId);
61662                     var tags = Object.assign({}, entity.tags); // shallow copy
61663
61664                     for (var key in tagSuggestingArea) {
61665                       delete tags[key];
61666                     }
61667
61668                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_tag.annotation'));
61669                   }
61670                 }));
61671                 return fixes;
61672               }
61673             });
61674
61675             function showReference(selection) {
61676               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.tag_suggests_area.reference'));
61677             }
61678           }
61679
61680           function vertexTaggedAsPointIssue(entity, graph) {
61681             // we only care about nodes
61682             if (entity.type !== 'node') return null; // ignore tagless points
61683
61684             if (Object.keys(entity.tags).length === 0) return null; // address lines are special so just ignore them
61685
61686             if (entity.isOnAddressLine(graph)) return null;
61687             var geometry = entity.geometry(graph);
61688             var allowedGeometries = osmNodeGeometriesForTags(entity.tags);
61689
61690             if (geometry === 'point' && !allowedGeometries.point && allowedGeometries.vertex) {
61691               return new validationIssue({
61692                 type: type,
61693                 subtype: 'vertex_as_point',
61694                 severity: 'warning',
61695                 message: function message(context) {
61696                   var entity = context.hasEntity(this.entityIds[0]);
61697                   return entity ? _t.html('issues.vertex_as_point.message', {
61698                     feature: utilDisplayLabel(entity, 'vertex')
61699                   }) : '';
61700                 },
61701                 reference: function showReference(selection) {
61702                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.vertex_as_point.reference'));
61703                 },
61704                 entityIds: [entity.id]
61705               });
61706             } else if (geometry === 'vertex' && !allowedGeometries.vertex && allowedGeometries.point) {
61707               return new validationIssue({
61708                 type: type,
61709                 subtype: 'point_as_vertex',
61710                 severity: 'warning',
61711                 message: function message(context) {
61712                   var entity = context.hasEntity(this.entityIds[0]);
61713                   return entity ? _t.html('issues.point_as_vertex.message', {
61714                     feature: utilDisplayLabel(entity, 'point')
61715                   }) : '';
61716                 },
61717                 reference: function showReference(selection) {
61718                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.point_as_vertex.reference'));
61719                 },
61720                 entityIds: [entity.id],
61721                 dynamicFixes: function dynamicFixes(context) {
61722                   var entityId = this.entityIds[0];
61723                   var extractOnClick = null;
61724
61725                   if (!context.hasHiddenConnections(entityId)) {
61726                     extractOnClick = function extractOnClick(context) {
61727                       var entityId = this.issue.entityIds[0];
61728                       var action = actionExtract(entityId);
61729                       context.perform(action, _t('operations.extract.annotation', {
61730                         n: 1
61731                       })); // re-enter mode to trigger updates
61732
61733                       context.enter(modeSelect(context, [action.getExtractedNodeID()]));
61734                     };
61735                   }
61736
61737                   return [new validationIssueFix({
61738                     icon: 'iD-operation-extract',
61739                     title: _t.html('issues.fix.extract_point.title'),
61740                     onClick: extractOnClick
61741                   })];
61742                 }
61743               });
61744             }
61745
61746             return null;
61747           }
61748
61749           function unclosedMultipolygonPartIssues(entity, graph) {
61750             if (entity.type !== 'relation' || !entity.isMultipolygon() || entity.isDegenerate() || // cannot determine issues for incompletely-downloaded relations
61751             !entity.isComplete(graph)) return null;
61752             var sequences = osmJoinWays(entity.members, graph);
61753             var issues = [];
61754
61755             for (var i in sequences) {
61756               var sequence = sequences[i];
61757               if (!sequence.nodes) continue;
61758               var firstNode = sequence.nodes[0];
61759               var lastNode = sequence.nodes[sequence.nodes.length - 1]; // part is closed if the first and last nodes are the same
61760
61761               if (firstNode === lastNode) continue;
61762               var issue = new validationIssue({
61763                 type: type,
61764                 subtype: 'unclosed_multipolygon_part',
61765                 severity: 'warning',
61766                 message: function message(context) {
61767                   var entity = context.hasEntity(this.entityIds[0]);
61768                   return entity ? _t.html('issues.unclosed_multipolygon_part.message', {
61769                     feature: utilDisplayLabel(entity, context.graph())
61770                   }) : '';
61771                 },
61772                 reference: showReference,
61773                 loc: sequence.nodes[0].loc,
61774                 entityIds: [entity.id],
61775                 hash: sequence.map(function (way) {
61776                   return way.id;
61777                 }).join()
61778               });
61779               issues.push(issue);
61780             }
61781
61782             return issues;
61783
61784             function showReference(selection) {
61785               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.unclosed_multipolygon_part.reference'));
61786             }
61787           }
61788
61789           var validation = function checkMismatchedGeometry(entity, graph) {
61790             var issues = [vertexTaggedAsPointIssue(entity, graph), lineTaggedAsAreaIssue(entity)];
61791             issues = issues.concat(unclosedMultipolygonPartIssues(entity, graph));
61792             return issues.filter(Boolean);
61793           };
61794
61795           validation.type = type;
61796           return validation;
61797         }
61798
61799         function validationMissingRole() {
61800           var type = 'missing_role';
61801
61802           var validation = function checkMissingRole(entity, graph) {
61803             var issues = [];
61804
61805             if (entity.type === 'way') {
61806               graph.parentRelations(entity).forEach(function (relation) {
61807                 if (!relation.isMultipolygon()) return;
61808                 var member = relation.memberById(entity.id);
61809
61810                 if (member && isMissingRole(member)) {
61811                   issues.push(makeIssue(entity, relation, member));
61812                 }
61813               });
61814             } else if (entity.type === 'relation' && entity.isMultipolygon()) {
61815               entity.indexedMembers().forEach(function (member) {
61816                 var way = graph.hasEntity(member.id);
61817
61818                 if (way && isMissingRole(member)) {
61819                   issues.push(makeIssue(way, entity, member));
61820                 }
61821               });
61822             }
61823
61824             return issues;
61825           };
61826
61827           function isMissingRole(member) {
61828             return !member.role || !member.role.trim().length;
61829           }
61830
61831           function makeIssue(way, relation, member) {
61832             return new validationIssue({
61833               type: type,
61834               severity: 'warning',
61835               message: function message(context) {
61836                 var member = context.hasEntity(this.entityIds[1]),
61837                     relation = context.hasEntity(this.entityIds[0]);
61838                 return member && relation ? _t.html('issues.missing_role.message', {
61839                   member: utilDisplayLabel(member, context.graph()),
61840                   relation: utilDisplayLabel(relation, context.graph())
61841                 }) : '';
61842               },
61843               reference: showReference,
61844               entityIds: [relation.id, way.id],
61845               data: {
61846                 member: member
61847               },
61848               hash: member.index.toString(),
61849               dynamicFixes: function dynamicFixes() {
61850                 return [makeAddRoleFix('inner'), makeAddRoleFix('outer'), new validationIssueFix({
61851                   icon: 'iD-operation-delete',
61852                   title: _t.html('issues.fix.remove_from_relation.title'),
61853                   onClick: function onClick(context) {
61854                     context.perform(actionDeleteMember(this.issue.entityIds[0], this.issue.data.member.index), _t('operations.delete_member.annotation', {
61855                       n: 1
61856                     }));
61857                   }
61858                 })];
61859               }
61860             });
61861
61862             function showReference(selection) {
61863               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.missing_role.multipolygon.reference'));
61864             }
61865           }
61866
61867           function makeAddRoleFix(role) {
61868             return new validationIssueFix({
61869               title: _t.html('issues.fix.set_as_' + role + '.title'),
61870               onClick: function onClick(context) {
61871                 var oldMember = this.issue.data.member;
61872                 var member = {
61873                   id: this.issue.entityIds[1],
61874                   type: oldMember.type,
61875                   role: role
61876                 };
61877                 context.perform(actionChangeMember(this.issue.entityIds[0], member, oldMember.index), _t('operations.change_role.annotation', {
61878                   n: 1
61879                 }));
61880               }
61881             });
61882           }
61883
61884           validation.type = type;
61885           return validation;
61886         }
61887
61888         function validationMissingTag(context) {
61889           var type = 'missing_tag';
61890
61891           function hasDescriptiveTags(entity, graph) {
61892             var keys = Object.keys(entity.tags).filter(function (k) {
61893               if (k === 'area' || k === 'name') {
61894                 return false;
61895               } else {
61896                 return osmIsInterestingTag(k);
61897               }
61898             });
61899
61900             if (entity.type === 'relation' && keys.length === 1 && entity.tags.type === 'multipolygon') {
61901               // this relation's only interesting tag just says its a multipolygon,
61902               // which is not descriptive enough
61903               // It's okay for a simple multipolygon to have no descriptive tags
61904               // if its outer way has them (old model, see `outdated_tags.js`)
61905               return osmOldMultipolygonOuterMemberOfRelation(entity, graph);
61906             }
61907
61908             return keys.length > 0;
61909           }
61910
61911           function isUnknownRoad(entity) {
61912             return entity.type === 'way' && entity.tags.highway === 'road';
61913           }
61914
61915           function isUntypedRelation(entity) {
61916             return entity.type === 'relation' && !entity.tags.type;
61917           }
61918
61919           var validation = function checkMissingTag(entity, graph) {
61920             var subtype;
61921             var osm = context.connection();
61922             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
61923
61924             if (!isUnloadedNode && // allow untagged nodes that are part of ways
61925             entity.geometry(graph) !== 'vertex' && // allow untagged entities that are part of relations
61926             !entity.hasParentRelations(graph)) {
61927               if (Object.keys(entity.tags).length === 0) {
61928                 subtype = 'any';
61929               } else if (!hasDescriptiveTags(entity, graph)) {
61930                 subtype = 'descriptive';
61931               } else if (isUntypedRelation(entity)) {
61932                 subtype = 'relation_type';
61933               }
61934             } // flag an unknown road even if it's a member of a relation
61935
61936
61937             if (!subtype && isUnknownRoad(entity)) {
61938               subtype = 'highway_classification';
61939             }
61940
61941             if (!subtype) return [];
61942             var messageID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag.' + subtype;
61943             var referenceID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag'; // can always delete if the user created it in the first place..
61944
61945             var canDelete = entity.version === undefined || entity.v !== undefined;
61946             var severity = canDelete && subtype !== 'highway_classification' ? 'error' : 'warning';
61947             return [new validationIssue({
61948               type: type,
61949               subtype: subtype,
61950               severity: severity,
61951               message: function message(context) {
61952                 var entity = context.hasEntity(this.entityIds[0]);
61953                 return entity ? _t.html('issues.' + messageID + '.message', {
61954                   feature: utilDisplayLabel(entity, context.graph())
61955                 }) : '';
61956               },
61957               reference: showReference,
61958               entityIds: [entity.id],
61959               dynamicFixes: function dynamicFixes(context) {
61960                 var fixes = [];
61961                 var selectFixType = subtype === 'highway_classification' ? 'select_road_type' : 'select_preset';
61962                 fixes.push(new validationIssueFix({
61963                   icon: 'iD-icon-search',
61964                   title: _t.html('issues.fix.' + selectFixType + '.title'),
61965                   onClick: function onClick(context) {
61966                     context.ui().sidebar.showPresetList();
61967                   }
61968                 }));
61969                 var deleteOnClick;
61970                 var id = this.entityIds[0];
61971                 var operation = operationDelete(context, [id]);
61972                 var disabledReasonID = operation.disabled();
61973
61974                 if (!disabledReasonID) {
61975                   deleteOnClick = function deleteOnClick(context) {
61976                     var id = this.issue.entityIds[0];
61977                     var operation = operationDelete(context, [id]);
61978
61979                     if (!operation.disabled()) {
61980                       operation();
61981                     }
61982                   };
61983                 }
61984
61985                 fixes.push(new validationIssueFix({
61986                   icon: 'iD-operation-delete',
61987                   title: _t.html('issues.fix.delete_feature.title'),
61988                   disabledReason: disabledReasonID ? _t('operations.delete.' + disabledReasonID + '.single') : undefined,
61989                   onClick: deleteOnClick
61990                 }));
61991                 return fixes;
61992               }
61993             })];
61994
61995             function showReference(selection) {
61996               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.' + referenceID + '.reference'));
61997             }
61998           };
61999
62000           validation.type = type;
62001           return validation;
62002         }
62003
62004         var simplify = function simplify(str) {
62005           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());
62006         };
62007
62008         // {
62009         //   kvnd:        "amenity/fast_food|Thaï Express~(North America)",
62010         //   kvn:         "amenity/fast_food|Thaï Express",
62011         //   kv:          "amenity/fast_food",
62012         //   k:           "amenity",
62013         //   v:           "fast_food",
62014         //   n:           "Thaï Express",
62015         //   d:           "(North America)",
62016         //   nsimple:     "thaiexpress",
62017         //   kvnnsimple:  "amenity/fast_food|thaiexpress"
62018         // }
62019
62020         var to_parts = function to_parts(kvnd) {
62021           var parts = {};
62022           parts.kvnd = kvnd;
62023           var kvndparts = kvnd.split('~', 2);
62024           if (kvndparts.length > 1) parts.d = kvndparts[1];
62025           parts.kvn = kvndparts[0];
62026           var kvnparts = parts.kvn.split('|', 2);
62027           if (kvnparts.length > 1) parts.n = kvnparts[1];
62028           parts.kv = kvnparts[0];
62029           var kvparts = parts.kv.split('/', 2);
62030           parts.k = kvparts[0];
62031           parts.v = kvparts[1];
62032           parts.nsimple = simplify(parts.n);
62033           parts.kvnsimple = parts.kv + '|' + parts.nsimple;
62034           return parts;
62035         };
62036
62037         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"]};
62038         var require$$0 = {
62039         matchGroups: matchGroups
62040         };
62041
62042         var matchGroups$1 = require$$0.matchGroups;
62043
62044         var matcher$1 = function matcher() {
62045           var _warnings = []; // array of match conflict pairs
62046
62047           var _ambiguous = {};
62048           var _matchIndex = {};
62049           var matcher = {}; // Create an index of all the keys/simplenames for fast matching
62050
62051           matcher.buildMatchIndex = function (brands) {
62052             // two passes - once for primary names, once for secondary/alternate names
62053             Object.keys(brands).forEach(function (kvnd) {
62054               return insertNames(kvnd, 'primary');
62055             });
62056             Object.keys(brands).forEach(function (kvnd) {
62057               return insertNames(kvnd, 'secondary');
62058             });
62059
62060             function insertNames(kvnd, which) {
62061               var obj = brands[kvnd];
62062               var parts = to_parts(kvnd); // Exit early for ambiguous names in the second pass.
62063               // They were collected in the first pass and we don't gather alt names for them.
62064
62065               if (which === 'secondary' && parts.d) return;
62066
62067               if (obj.countryCodes) {
62068                 parts.countryCodes = obj.countryCodes.slice(); // copy
62069               }
62070
62071               var nomatches = obj.nomatch || [];
62072
62073               if (nomatches.some(function (s) {
62074                 return s === kvnd;
62075               })) {
62076                 console.log("WARNING match/nomatch conflict for ".concat(kvnd));
62077                 return;
62078               }
62079
62080               var match_kv = [parts.kv].concat(obj.matchTags || []).concat(["".concat(parts.k, "/yes"), "building/yes"]) // #3454 - match some generic tags
62081               .map(function (s) {
62082                 return s.toLowerCase();
62083               });
62084               var match_nsimple = [];
62085
62086               if (which === 'primary') {
62087                 match_nsimple = [parts.n].concat(obj.matchNames || []).concat(obj.tags.official_name || []) // #2732 - match alternate names
62088                 .map(simplify);
62089               } else if (which === 'secondary') {
62090                 match_nsimple = [].concat(obj.tags.alt_name || []) // #2732 - match alternate names
62091                 .concat(obj.tags.short_name || []) // #2732 - match alternate names
62092                 .map(simplify);
62093               }
62094
62095               if (!match_nsimple.length) return; // nothing to do
62096
62097               match_kv.forEach(function (kv) {
62098                 match_nsimple.forEach(function (nsimple) {
62099                   if (parts.d) {
62100                     // Known ambiguous names with disambiguation string ~(USA) / ~(Canada)
62101                     // FIXME: Name collisions will overwrite the initial entry (ok for now)
62102                     if (!_ambiguous[kv]) _ambiguous[kv] = {};
62103                     _ambiguous[kv][nsimple] = parts;
62104                   } else {
62105                     // Names we mostly expect to be unique..
62106                     if (!_matchIndex[kv]) _matchIndex[kv] = {};
62107                     var m = _matchIndex[kv][nsimple];
62108
62109                     if (m) {
62110                       // There already is a match for this name, skip it
62111                       // Warn if we detect collisions in a primary name.
62112                       // Skip warning if a secondary name or a generic `*=yes` tag - #2972 / #3454
62113                       if (which === 'primary' && !/\/yes$/.test(kv)) {
62114                         _warnings.push([m.kvnd, "".concat(kvnd, " (").concat(kv, "/").concat(nsimple, ")")]);
62115                       }
62116                     } else {
62117                       _matchIndex[kv][nsimple] = parts; // insert
62118                     }
62119                   }
62120                 });
62121               });
62122             }
62123           }; // pass a `key`, `value`, `name` and return the best match,
62124           // `countryCode` optional (if supplied, must match that too)
62125
62126
62127           matcher.matchKVN = function (key, value, name, countryCode) {
62128             return matcher.matchParts(to_parts("".concat(key, "/").concat(value, "|").concat(name)), countryCode);
62129           }; // pass a parts object and return the best match,
62130           // `countryCode` optional (if supplied, must match that too)
62131
62132
62133           matcher.matchParts = function (parts, countryCode) {
62134             var match = null;
62135             var inGroup = false; // fixme: we currently return a single match for ambiguous
62136
62137             match = _ambiguous[parts.kv] && _ambiguous[parts.kv][parts.nsimple];
62138             if (match && matchesCountryCode(match)) return match; // try to return an exact match
62139
62140             match = _matchIndex[parts.kv] && _matchIndex[parts.kv][parts.nsimple];
62141             if (match && matchesCountryCode(match)) return match; // look in match groups
62142
62143             for (var mg in matchGroups$1) {
62144               var matchGroup = matchGroups$1[mg];
62145               match = null;
62146               inGroup = false;
62147
62148               for (var i = 0; i < matchGroup.length; i++) {
62149                 var otherkv = matchGroup[i].toLowerCase();
62150
62151                 if (!inGroup) {
62152                   inGroup = otherkv === parts.kv;
62153                 }
62154
62155                 if (!match) {
62156                   // fixme: we currently return a single match for ambiguous
62157                   match = _ambiguous[otherkv] && _ambiguous[otherkv][parts.nsimple];
62158                 }
62159
62160                 if (!match) {
62161                   match = _matchIndex[otherkv] && _matchIndex[otherkv][parts.nsimple];
62162                 }
62163
62164                 if (match && !matchesCountryCode(match)) {
62165                   match = null;
62166                 }
62167
62168                 if (inGroup && match) {
62169                   return match;
62170                 }
62171               }
62172             }
62173
62174             return null;
62175
62176             function matchesCountryCode(match) {
62177               if (!countryCode) return true;
62178               if (!match.countryCodes) return true;
62179               return match.countryCodes.indexOf(countryCode) !== -1;
62180             }
62181           };
62182
62183           matcher.getWarnings = function () {
62184             return _warnings;
62185           };
62186
62187           return matcher;
62188         };
62189
62190         var fromCharCode = String.fromCharCode;
62191         var nativeFromCodePoint = String.fromCodePoint;
62192
62193         // length should be 1, old FF problem
62194         var INCORRECT_LENGTH = !!nativeFromCodePoint && nativeFromCodePoint.length != 1;
62195
62196         // `String.fromCodePoint` method
62197         // https://tc39.github.io/ecma262/#sec-string.fromcodepoint
62198         _export({ target: 'String', stat: true, forced: INCORRECT_LENGTH }, {
62199           fromCodePoint: function fromCodePoint(x) { // eslint-disable-line no-unused-vars
62200             var elements = [];
62201             var length = arguments.length;
62202             var i = 0;
62203             var code;
62204             while (length > i) {
62205               code = +arguments[i++];
62206               if (toAbsoluteIndex(code, 0x10FFFF) !== code) throw RangeError(code + ' is not a valid code point');
62207               elements.push(code < 0x10000
62208                 ? fromCharCode(code)
62209                 : fromCharCode(((code -= 0x10000) >> 10) + 0xD800, code % 0x400 + 0xDC00)
62210               );
62211             } return elements.join('');
62212           }
62213         });
62214
62215         var quickselect$2 = createCommonjsModule(function (module, exports) {
62216           (function (global, factory) {
62217              module.exports = factory() ;
62218           })(commonjsGlobal, function () {
62219
62220             function quickselect(arr, k, left, right, compare) {
62221               quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
62222             }
62223
62224             function quickselectStep(arr, k, left, right, compare) {
62225               while (right > left) {
62226                 if (right - left > 600) {
62227                   var n = right - left + 1;
62228                   var m = k - left + 1;
62229                   var z = Math.log(n);
62230                   var s = 0.5 * Math.exp(2 * z / 3);
62231                   var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
62232                   var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
62233                   var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
62234                   quickselectStep(arr, k, newLeft, newRight, compare);
62235                 }
62236
62237                 var t = arr[k];
62238                 var i = left;
62239                 var j = right;
62240                 swap(arr, left, k);
62241                 if (compare(arr[right], t) > 0) swap(arr, left, right);
62242
62243                 while (i < j) {
62244                   swap(arr, i, j);
62245                   i++;
62246                   j--;
62247
62248                   while (compare(arr[i], t) < 0) {
62249                     i++;
62250                   }
62251
62252                   while (compare(arr[j], t) > 0) {
62253                     j--;
62254                   }
62255                 }
62256
62257                 if (compare(arr[left], t) === 0) swap(arr, left, j);else {
62258                   j++;
62259                   swap(arr, j, right);
62260                 }
62261                 if (j <= k) left = j + 1;
62262                 if (k <= j) right = j - 1;
62263               }
62264             }
62265
62266             function swap(arr, i, j) {
62267               var tmp = arr[i];
62268               arr[i] = arr[j];
62269               arr[j] = tmp;
62270             }
62271
62272             function defaultCompare(a, b) {
62273               return a < b ? -1 : a > b ? 1 : 0;
62274             }
62275
62276             return quickselect;
62277           });
62278         });
62279
62280         var rbush_1 = rbush;
62281         var _default$2 = rbush;
62282
62283         function rbush(maxEntries, format) {
62284           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
62285
62286           this._maxEntries = Math.max(4, maxEntries || 9);
62287           this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
62288
62289           if (format) {
62290             this._initFormat(format);
62291           }
62292
62293           this.clear();
62294         }
62295
62296         rbush.prototype = {
62297           all: function all() {
62298             return this._all(this.data, []);
62299           },
62300           search: function search(bbox) {
62301             var node = this.data,
62302                 result = [],
62303                 toBBox = this.toBBox;
62304             if (!intersects$1(bbox, node)) return result;
62305             var nodesToSearch = [],
62306                 i,
62307                 len,
62308                 child,
62309                 childBBox;
62310
62311             while (node) {
62312               for (i = 0, len = node.children.length; i < len; i++) {
62313                 child = node.children[i];
62314                 childBBox = node.leaf ? toBBox(child) : child;
62315
62316                 if (intersects$1(bbox, childBBox)) {
62317                   if (node.leaf) result.push(child);else if (contains$1(bbox, childBBox)) this._all(child, result);else nodesToSearch.push(child);
62318                 }
62319               }
62320
62321               node = nodesToSearch.pop();
62322             }
62323
62324             return result;
62325           },
62326           collides: function collides(bbox) {
62327             var node = this.data,
62328                 toBBox = this.toBBox;
62329             if (!intersects$1(bbox, node)) return false;
62330             var nodesToSearch = [],
62331                 i,
62332                 len,
62333                 child,
62334                 childBBox;
62335
62336             while (node) {
62337               for (i = 0, len = node.children.length; i < len; i++) {
62338                 child = node.children[i];
62339                 childBBox = node.leaf ? toBBox(child) : child;
62340
62341                 if (intersects$1(bbox, childBBox)) {
62342                   if (node.leaf || contains$1(bbox, childBBox)) return true;
62343                   nodesToSearch.push(child);
62344                 }
62345               }
62346
62347               node = nodesToSearch.pop();
62348             }
62349
62350             return false;
62351           },
62352           load: function load(data) {
62353             if (!(data && data.length)) return this;
62354
62355             if (data.length < this._minEntries) {
62356               for (var i = 0, len = data.length; i < len; i++) {
62357                 this.insert(data[i]);
62358               }
62359
62360               return this;
62361             } // recursively build the tree with the given data from scratch using OMT algorithm
62362
62363
62364             var node = this._build(data.slice(), 0, data.length - 1, 0);
62365
62366             if (!this.data.children.length) {
62367               // save as is if tree is empty
62368               this.data = node;
62369             } else if (this.data.height === node.height) {
62370               // split root if trees have the same height
62371               this._splitRoot(this.data, node);
62372             } else {
62373               if (this.data.height < node.height) {
62374                 // swap trees if inserted one is bigger
62375                 var tmpNode = this.data;
62376                 this.data = node;
62377                 node = tmpNode;
62378               } // insert the small tree into the large tree at appropriate level
62379
62380
62381               this._insert(node, this.data.height - node.height - 1, true);
62382             }
62383
62384             return this;
62385           },
62386           insert: function insert(item) {
62387             if (item) this._insert(item, this.data.height - 1);
62388             return this;
62389           },
62390           clear: function clear() {
62391             this.data = createNode$1([]);
62392             return this;
62393           },
62394           remove: function remove(item, equalsFn) {
62395             if (!item) return this;
62396             var node = this.data,
62397                 bbox = this.toBBox(item),
62398                 path = [],
62399                 indexes = [],
62400                 i,
62401                 parent,
62402                 index,
62403                 goingUp; // depth-first iterative tree traversal
62404
62405             while (node || path.length) {
62406               if (!node) {
62407                 // go up
62408                 node = path.pop();
62409                 parent = path[path.length - 1];
62410                 i = indexes.pop();
62411                 goingUp = true;
62412               }
62413
62414               if (node.leaf) {
62415                 // check current node
62416                 index = findItem$1(item, node.children, equalsFn);
62417
62418                 if (index !== -1) {
62419                   // item found, remove the item and condense tree upwards
62420                   node.children.splice(index, 1);
62421                   path.push(node);
62422
62423                   this._condense(path);
62424
62425                   return this;
62426                 }
62427               }
62428
62429               if (!goingUp && !node.leaf && contains$1(node, bbox)) {
62430                 // go down
62431                 path.push(node);
62432                 indexes.push(i);
62433                 i = 0;
62434                 parent = node;
62435                 node = node.children[0];
62436               } else if (parent) {
62437                 // go right
62438                 i++;
62439                 node = parent.children[i];
62440                 goingUp = false;
62441               } else node = null; // nothing found
62442
62443             }
62444
62445             return this;
62446           },
62447           toBBox: function toBBox(item) {
62448             return item;
62449           },
62450           compareMinX: compareNodeMinX$1,
62451           compareMinY: compareNodeMinY$1,
62452           toJSON: function toJSON() {
62453             return this.data;
62454           },
62455           fromJSON: function fromJSON(data) {
62456             this.data = data;
62457             return this;
62458           },
62459           _all: function _all(node, result) {
62460             var nodesToSearch = [];
62461
62462             while (node) {
62463               if (node.leaf) result.push.apply(result, node.children);else nodesToSearch.push.apply(nodesToSearch, node.children);
62464               node = nodesToSearch.pop();
62465             }
62466
62467             return result;
62468           },
62469           _build: function _build(items, left, right, height) {
62470             var N = right - left + 1,
62471                 M = this._maxEntries,
62472                 node;
62473
62474             if (N <= M) {
62475               // reached leaf level; return leaf
62476               node = createNode$1(items.slice(left, right + 1));
62477               calcBBox$1(node, this.toBBox);
62478               return node;
62479             }
62480
62481             if (!height) {
62482               // target height of the bulk-loaded tree
62483               height = Math.ceil(Math.log(N) / Math.log(M)); // target number of root entries to maximize storage utilization
62484
62485               M = Math.ceil(N / Math.pow(M, height - 1));
62486             }
62487
62488             node = createNode$1([]);
62489             node.leaf = false;
62490             node.height = height; // split the items into M mostly square tiles
62491
62492             var N2 = Math.ceil(N / M),
62493                 N1 = N2 * Math.ceil(Math.sqrt(M)),
62494                 i,
62495                 j,
62496                 right2,
62497                 right3;
62498             multiSelect$1(items, left, right, N1, this.compareMinX);
62499
62500             for (i = left; i <= right; i += N1) {
62501               right2 = Math.min(i + N1 - 1, right);
62502               multiSelect$1(items, i, right2, N2, this.compareMinY);
62503
62504               for (j = i; j <= right2; j += N2) {
62505                 right3 = Math.min(j + N2 - 1, right2); // pack each entry recursively
62506
62507                 node.children.push(this._build(items, j, right3, height - 1));
62508               }
62509             }
62510
62511             calcBBox$1(node, this.toBBox);
62512             return node;
62513           },
62514           _chooseSubtree: function _chooseSubtree(bbox, node, level, path) {
62515             var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
62516
62517             while (true) {
62518               path.push(node);
62519               if (node.leaf || path.length - 1 === level) break;
62520               minArea = minEnlargement = Infinity;
62521
62522               for (i = 0, len = node.children.length; i < len; i++) {
62523                 child = node.children[i];
62524                 area = bboxArea$1(child);
62525                 enlargement = enlargedArea$1(bbox, child) - area; // choose entry with the least area enlargement
62526
62527                 if (enlargement < minEnlargement) {
62528                   minEnlargement = enlargement;
62529                   minArea = area < minArea ? area : minArea;
62530                   targetNode = child;
62531                 } else if (enlargement === minEnlargement) {
62532                   // otherwise choose one with the smallest area
62533                   if (area < minArea) {
62534                     minArea = area;
62535                     targetNode = child;
62536                   }
62537                 }
62538               }
62539
62540               node = targetNode || node.children[0];
62541             }
62542
62543             return node;
62544           },
62545           _insert: function _insert(item, level, isNode) {
62546             var toBBox = this.toBBox,
62547                 bbox = isNode ? item : toBBox(item),
62548                 insertPath = []; // find the best node for accommodating the item, saving all nodes along the path too
62549
62550             var node = this._chooseSubtree(bbox, this.data, level, insertPath); // put the item into the node
62551
62552
62553             node.children.push(item);
62554             extend$3(node, bbox); // split on node overflow; propagate upwards if necessary
62555
62556             while (level >= 0) {
62557               if (insertPath[level].children.length > this._maxEntries) {
62558                 this._split(insertPath, level);
62559
62560                 level--;
62561               } else break;
62562             } // adjust bboxes along the insertion path
62563
62564
62565             this._adjustParentBBoxes(bbox, insertPath, level);
62566           },
62567           // split overflowed node into two
62568           _split: function _split(insertPath, level) {
62569             var node = insertPath[level],
62570                 M = node.children.length,
62571                 m = this._minEntries;
62572
62573             this._chooseSplitAxis(node, m, M);
62574
62575             var splitIndex = this._chooseSplitIndex(node, m, M);
62576
62577             var newNode = createNode$1(node.children.splice(splitIndex, node.children.length - splitIndex));
62578             newNode.height = node.height;
62579             newNode.leaf = node.leaf;
62580             calcBBox$1(node, this.toBBox);
62581             calcBBox$1(newNode, this.toBBox);
62582             if (level) insertPath[level - 1].children.push(newNode);else this._splitRoot(node, newNode);
62583           },
62584           _splitRoot: function _splitRoot(node, newNode) {
62585             // split root node
62586             this.data = createNode$1([node, newNode]);
62587             this.data.height = node.height + 1;
62588             this.data.leaf = false;
62589             calcBBox$1(this.data, this.toBBox);
62590           },
62591           _chooseSplitIndex: function _chooseSplitIndex(node, m, M) {
62592             var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
62593             minOverlap = minArea = Infinity;
62594
62595             for (i = m; i <= M - m; i++) {
62596               bbox1 = distBBox$1(node, 0, i, this.toBBox);
62597               bbox2 = distBBox$1(node, i, M, this.toBBox);
62598               overlap = intersectionArea$1(bbox1, bbox2);
62599               area = bboxArea$1(bbox1) + bboxArea$1(bbox2); // choose distribution with minimum overlap
62600
62601               if (overlap < minOverlap) {
62602                 minOverlap = overlap;
62603                 index = i;
62604                 minArea = area < minArea ? area : minArea;
62605               } else if (overlap === minOverlap) {
62606                 // otherwise choose distribution with minimum area
62607                 if (area < minArea) {
62608                   minArea = area;
62609                   index = i;
62610                 }
62611               }
62612             }
62613
62614             return index;
62615           },
62616           // sorts node children by the best axis for split
62617           _chooseSplitAxis: function _chooseSplitAxis(node, m, M) {
62618             var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX$1,
62619                 compareMinY = node.leaf ? this.compareMinY : compareNodeMinY$1,
62620                 xMargin = this._allDistMargin(node, m, M, compareMinX),
62621                 yMargin = this._allDistMargin(node, m, M, compareMinY); // if total distributions margin value is minimal for x, sort by minX,
62622             // otherwise it's already sorted by minY
62623
62624
62625             if (xMargin < yMargin) node.children.sort(compareMinX);
62626           },
62627           // total margin of all possible split distributions where each node is at least m full
62628           _allDistMargin: function _allDistMargin(node, m, M, compare) {
62629             node.children.sort(compare);
62630             var toBBox = this.toBBox,
62631                 leftBBox = distBBox$1(node, 0, m, toBBox),
62632                 rightBBox = distBBox$1(node, M - m, M, toBBox),
62633                 margin = bboxMargin$1(leftBBox) + bboxMargin$1(rightBBox),
62634                 i,
62635                 child;
62636
62637             for (i = m; i < M - m; i++) {
62638               child = node.children[i];
62639               extend$3(leftBBox, node.leaf ? toBBox(child) : child);
62640               margin += bboxMargin$1(leftBBox);
62641             }
62642
62643             for (i = M - m - 1; i >= m; i--) {
62644               child = node.children[i];
62645               extend$3(rightBBox, node.leaf ? toBBox(child) : child);
62646               margin += bboxMargin$1(rightBBox);
62647             }
62648
62649             return margin;
62650           },
62651           _adjustParentBBoxes: function _adjustParentBBoxes(bbox, path, level) {
62652             // adjust bboxes along the given tree path
62653             for (var i = level; i >= 0; i--) {
62654               extend$3(path[i], bbox);
62655             }
62656           },
62657           _condense: function _condense(path) {
62658             // go through the path, removing empty nodes and updating bboxes
62659             for (var i = path.length - 1, siblings; i >= 0; i--) {
62660               if (path[i].children.length === 0) {
62661                 if (i > 0) {
62662                   siblings = path[i - 1].children;
62663                   siblings.splice(siblings.indexOf(path[i]), 1);
62664                 } else this.clear();
62665               } else calcBBox$1(path[i], this.toBBox);
62666             }
62667           },
62668           _initFormat: function _initFormat(format) {
62669             // data format (minX, minY, maxX, maxY accessors)
62670             // uses eval-type function compilation instead of just accepting a toBBox function
62671             // because the algorithms are very sensitive to sorting functions performance,
62672             // so they should be dead simple and without inner calls
62673             var compareArr = ['return a', ' - b', ';'];
62674             this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
62675             this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
62676             this.toBBox = new Function('a', 'return {minX: a' + format[0] + ', minY: a' + format[1] + ', maxX: a' + format[2] + ', maxY: a' + format[3] + '};');
62677           }
62678         };
62679
62680         function findItem$1(item, items, equalsFn) {
62681           if (!equalsFn) return items.indexOf(item);
62682
62683           for (var i = 0; i < items.length; i++) {
62684             if (equalsFn(item, items[i])) return i;
62685           }
62686
62687           return -1;
62688         } // calculate node's bbox from bboxes of its children
62689
62690
62691         function calcBBox$1(node, toBBox) {
62692           distBBox$1(node, 0, node.children.length, toBBox, node);
62693         } // min bounding rectangle of node children from k to p-1
62694
62695
62696         function distBBox$1(node, k, p, toBBox, destNode) {
62697           if (!destNode) destNode = createNode$1(null);
62698           destNode.minX = Infinity;
62699           destNode.minY = Infinity;
62700           destNode.maxX = -Infinity;
62701           destNode.maxY = -Infinity;
62702
62703           for (var i = k, child; i < p; i++) {
62704             child = node.children[i];
62705             extend$3(destNode, node.leaf ? toBBox(child) : child);
62706           }
62707
62708           return destNode;
62709         }
62710
62711         function extend$3(a, b) {
62712           a.minX = Math.min(a.minX, b.minX);
62713           a.minY = Math.min(a.minY, b.minY);
62714           a.maxX = Math.max(a.maxX, b.maxX);
62715           a.maxY = Math.max(a.maxY, b.maxY);
62716           return a;
62717         }
62718
62719         function compareNodeMinX$1(a, b) {
62720           return a.minX - b.minX;
62721         }
62722
62723         function compareNodeMinY$1(a, b) {
62724           return a.minY - b.minY;
62725         }
62726
62727         function bboxArea$1(a) {
62728           return (a.maxX - a.minX) * (a.maxY - a.minY);
62729         }
62730
62731         function bboxMargin$1(a) {
62732           return a.maxX - a.minX + (a.maxY - a.minY);
62733         }
62734
62735         function enlargedArea$1(a, b) {
62736           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));
62737         }
62738
62739         function intersectionArea$1(a, b) {
62740           var minX = Math.max(a.minX, b.minX),
62741               minY = Math.max(a.minY, b.minY),
62742               maxX = Math.min(a.maxX, b.maxX),
62743               maxY = Math.min(a.maxY, b.maxY);
62744           return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
62745         }
62746
62747         function contains$1(a, b) {
62748           return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
62749         }
62750
62751         function intersects$1(a, b) {
62752           return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
62753         }
62754
62755         function createNode$1(children) {
62756           return {
62757             children: children,
62758             height: 1,
62759             leaf: true,
62760             minX: Infinity,
62761             minY: Infinity,
62762             maxX: -Infinity,
62763             maxY: -Infinity
62764           };
62765         } // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
62766         // combines selection algorithm with binary divide & conquer approach
62767
62768
62769         function multiSelect$1(arr, left, right, n, compare) {
62770           var stack = [left, right],
62771               mid;
62772
62773           while (stack.length) {
62774             right = stack.pop();
62775             left = stack.pop();
62776             if (right - left <= n) continue;
62777             mid = left + Math.ceil((right - left) / n / 2) * n;
62778             quickselect$2(arr, mid, left, right, compare);
62779             stack.push(left, mid, mid, right);
62780           }
62781         }
62782         rbush_1["default"] = _default$2;
62783
62784         var lineclip_1$1 = lineclip$1;
62785         lineclip$1.polyline = lineclip$1;
62786         lineclip$1.polygon = polygonclip$1; // Cohen-Sutherland line clippign algorithm, adapted to efficiently
62787         // handle polylines rather than just segments
62788
62789         function lineclip$1(points, bbox, result) {
62790           var len = points.length,
62791               codeA = bitCode$1(points[0], bbox),
62792               part = [],
62793               i,
62794               a,
62795               b,
62796               codeB,
62797               lastCode;
62798           if (!result) result = [];
62799
62800           for (i = 1; i < len; i++) {
62801             a = points[i - 1];
62802             b = points[i];
62803             codeB = lastCode = bitCode$1(b, bbox);
62804
62805             while (true) {
62806               if (!(codeA | codeB)) {
62807                 // accept
62808                 part.push(a);
62809
62810                 if (codeB !== lastCode) {
62811                   // segment went outside
62812                   part.push(b);
62813
62814                   if (i < len - 1) {
62815                     // start a new line
62816                     result.push(part);
62817                     part = [];
62818                   }
62819                 } else if (i === len - 1) {
62820                   part.push(b);
62821                 }
62822
62823                 break;
62824               } else if (codeA & codeB) {
62825                 // trivial reject
62826                 break;
62827               } else if (codeA) {
62828                 // a outside, intersect with clip edge
62829                 a = intersect$1(a, b, codeA, bbox);
62830                 codeA = bitCode$1(a, bbox);
62831               } else {
62832                 // b outside
62833                 b = intersect$1(a, b, codeB, bbox);
62834                 codeB = bitCode$1(b, bbox);
62835               }
62836             }
62837
62838             codeA = lastCode;
62839           }
62840
62841           if (part.length) result.push(part);
62842           return result;
62843         } // Sutherland-Hodgeman polygon clipping algorithm
62844
62845
62846         function polygonclip$1(points, bbox) {
62847           var result, edge, prev, prevInside, i, p, inside; // clip against each side of the clip rectangle
62848
62849           for (edge = 1; edge <= 8; edge *= 2) {
62850             result = [];
62851             prev = points[points.length - 1];
62852             prevInside = !(bitCode$1(prev, bbox) & edge);
62853
62854             for (i = 0; i < points.length; i++) {
62855               p = points[i];
62856               inside = !(bitCode$1(p, bbox) & edge); // if segment goes through the clip window, add an intersection
62857
62858               if (inside !== prevInside) result.push(intersect$1(prev, p, edge, bbox));
62859               if (inside) result.push(p); // add a point if it's inside
62860
62861               prev = p;
62862               prevInside = inside;
62863             }
62864
62865             points = result;
62866             if (!points.length) break;
62867           }
62868
62869           return result;
62870         } // intersect a segment against one of the 4 lines that make up the bbox
62871
62872
62873         function intersect$1(a, b, edge, bbox) {
62874           return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] : // top
62875           edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] : // bottom
62876           edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] : // right
62877           edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] : // left
62878           null;
62879         } // bit code reflects the point position relative to the bbox:
62880         //         left  mid  right
62881         //    top  1001  1000  1010
62882         //    mid  0001  0000  0010
62883         // bottom  0101  0100  0110
62884
62885
62886         function bitCode$1(p, bbox) {
62887           var code = 0;
62888           if (p[0] < bbox[0]) code |= 1; // left
62889           else if (p[0] > bbox[2]) code |= 2; // right
62890
62891           if (p[1] < bbox[1]) code |= 4; // bottom
62892           else if (p[1] > bbox[3]) code |= 8; // top
62893
62894           return code;
62895         }
62896
62897         var whichPolygon_1 = whichPolygon;
62898
62899         function whichPolygon(data) {
62900           var bboxes = [];
62901
62902           for (var i = 0; i < data.features.length; i++) {
62903             var feature = data.features[i];
62904             var coords = feature.geometry.coordinates;
62905
62906             if (feature.geometry.type === 'Polygon') {
62907               bboxes.push(treeItem(coords, feature.properties));
62908             } else if (feature.geometry.type === 'MultiPolygon') {
62909               for (var j = 0; j < coords.length; j++) {
62910                 bboxes.push(treeItem(coords[j], feature.properties));
62911               }
62912             }
62913           }
62914
62915           var tree = rbush_1().load(bboxes);
62916
62917           function query(p, multi) {
62918             var output = [],
62919                 result = tree.search({
62920               minX: p[0],
62921               minY: p[1],
62922               maxX: p[0],
62923               maxY: p[1]
62924             });
62925
62926             for (var i = 0; i < result.length; i++) {
62927               if (insidePolygon(result[i].coords, p)) {
62928                 if (multi) output.push(result[i].props);else return result[i].props;
62929               }
62930             }
62931
62932             return multi && output.length ? output : null;
62933           }
62934
62935           query.tree = tree;
62936
62937           query.bbox = function queryBBox(bbox) {
62938             var output = [];
62939             var result = tree.search({
62940               minX: bbox[0],
62941               minY: bbox[1],
62942               maxX: bbox[2],
62943               maxY: bbox[3]
62944             });
62945
62946             for (var i = 0; i < result.length; i++) {
62947               if (polygonIntersectsBBox(result[i].coords, bbox)) {
62948                 output.push(result[i].props);
62949               }
62950             }
62951
62952             return output;
62953           };
62954
62955           return query;
62956         }
62957
62958         function polygonIntersectsBBox(polygon, bbox) {
62959           var bboxCenter = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
62960           if (insidePolygon(polygon, bboxCenter)) return true;
62961
62962           for (var i = 0; i < polygon.length; i++) {
62963             if (lineclip_1$1(polygon[i], bbox).length > 0) return true;
62964           }
62965
62966           return false;
62967         } // ray casting algorithm for detecting if point is in polygon
62968
62969
62970         function insidePolygon(rings, p) {
62971           var inside = false;
62972
62973           for (var i = 0, len = rings.length; i < len; i++) {
62974             var ring = rings[i];
62975
62976             for (var j = 0, len2 = ring.length, k = len2 - 1; j < len2; k = j++) {
62977               if (rayIntersect(p, ring[j], ring[k])) inside = !inside;
62978             }
62979           }
62980
62981           return inside;
62982         }
62983
62984         function rayIntersect(p, p1, p2) {
62985           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];
62986         }
62987
62988         function treeItem(coords, props) {
62989           var item = {
62990             minX: Infinity,
62991             minY: Infinity,
62992             maxX: -Infinity,
62993             maxY: -Infinity,
62994             coords: coords,
62995             props: props
62996           };
62997
62998           for (var i = 0; i < coords[0].length; i++) {
62999             var p = coords[0][i];
63000             item.minX = Math.min(item.minX, p[0]);
63001             item.minY = Math.min(item.minY, p[1]);
63002             item.maxX = Math.max(item.maxX, p[0]);
63003             item.maxY = Math.max(item.maxY, p[1]);
63004           }
63005
63006           return item;
63007         }
63008
63009         var type = "FeatureCollection";
63010         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]]]]}}];
63011         var rawBorders = {
63012         type: type,
63013         features: features
63014         };
63015
63016         var borders = rawBorders;
63017         var whichPolygonGetter = {};
63018         var featuresByCode = {};
63019         var idFilterRegex = /\bThe\b|\bthe\b|\band\b|\bof\b|[-_ .,()&[\]/]/g;
63020         var levels = ['subterritory', 'territory', 'country', 'intermediateRegion', 'subregion', 'region', 'union', 'world'];
63021         loadDerivedDataAndCaches(borders);
63022
63023         function loadDerivedDataAndCaches(borders) {
63024           var identifierProps = ['iso1A2', 'iso1A3', 'm49', 'wikidata', 'emojiFlag', 'nameEn'];
63025           var geometryFeatures = [];
63026
63027           for (var i in borders.features) {
63028             var _feature = borders.features[i];
63029             _feature.properties.id = _feature.properties.iso1A2 || _feature.properties.m49;
63030             loadM49(_feature);
63031             loadIsoStatus(_feature);
63032             loadLevel(_feature);
63033             loadGroups(_feature);
63034             loadRoadSpeedUnit(_feature);
63035             loadDriveSide(_feature);
63036             loadFlag(_feature);
63037             cacheFeatureByIDs(_feature);
63038             if (_feature.geometry) geometryFeatures.push(_feature);
63039           }
63040
63041           for (var _i in borders.features) {
63042             var _feature2 = borders.features[_i];
63043
63044             _feature2.properties.groups.sort(function (groupID1, groupID2) {
63045               return levels.indexOf(featuresByCode[groupID1].properties.level) - levels.indexOf(featuresByCode[groupID2].properties.level);
63046             });
63047
63048             loadMembersForGroupsOf(_feature2);
63049           }
63050
63051           var geometryOnlyCollection = {
63052             type: 'RegionFeatureCollection',
63053             features: geometryFeatures
63054           };
63055           whichPolygonGetter = whichPolygon_1(geometryOnlyCollection);
63056
63057           function loadGroups(feature) {
63058             var props = feature.properties;
63059
63060             if (!props.groups) {
63061               props.groups = [];
63062             }
63063
63064             if (props.country) {
63065               props.groups.push(props.country);
63066             }
63067
63068             if (props.m49 !== '001') {
63069               props.groups.push('001');
63070             }
63071           }
63072
63073           function loadM49(feature) {
63074             var props = feature.properties;
63075
63076             if (!props.m49 && props.iso1N3) {
63077               props.m49 = props.iso1N3;
63078             }
63079           }
63080
63081           function loadIsoStatus(feature) {
63082             var props = feature.properties;
63083
63084             if (!props.isoStatus && props.iso1A2) {
63085               props.isoStatus = 'official';
63086             }
63087           }
63088
63089           function loadLevel(feature) {
63090             var props = feature.properties;
63091             if (props.level) return;
63092
63093             if (!props.country) {
63094               props.level = 'country';
63095             } else if (props.isoStatus === 'official') {
63096               props.level = 'territory';
63097             } else {
63098               props.level = 'subterritory';
63099             }
63100           }
63101
63102           function loadRoadSpeedUnit(feature) {
63103             var props = feature.properties;
63104
63105             if (props.roadSpeedUnit === undefined && props.iso1A2 && props.iso1A2 !== 'EU') {
63106               props.roadSpeedUnit = 'km/h';
63107             }
63108           }
63109
63110           function loadDriveSide(feature) {
63111             var props = feature.properties;
63112
63113             if (props.driveSide === undefined && props.iso1A2 && props.iso1A2 !== 'EU') {
63114               props.driveSide = 'right';
63115             }
63116           }
63117
63118           function loadFlag(feature) {
63119             if (!feature.properties.iso1A2) return;
63120             var flag = feature.properties.iso1A2.replace(/./g, function (_char) {
63121               return String.fromCodePoint(_char.charCodeAt(0) + 127397);
63122             });
63123             feature.properties.emojiFlag = flag;
63124           }
63125
63126           function loadMembersForGroupsOf(feature) {
63127             var featureID = feature.properties.id;
63128             var standardizedGroupIDs = [];
63129
63130             for (var j in feature.properties.groups) {
63131               var groupID = feature.properties.groups[j];
63132               var groupFeature = featuresByCode[groupID];
63133               standardizedGroupIDs.push(groupFeature.properties.id);
63134
63135               if (groupFeature.properties.members) {
63136                 groupFeature.properties.members.push(featureID);
63137               } else {
63138                 groupFeature.properties.members = [featureID];
63139               }
63140             }
63141
63142             feature.properties.groups = standardizedGroupIDs;
63143           }
63144
63145           function cacheFeatureByIDs(feature) {
63146             for (var k in identifierProps) {
63147               var prop = identifierProps[k];
63148               var id = prop && feature.properties[prop];
63149
63150               if (id) {
63151                 id = id.replace(idFilterRegex, '').toUpperCase();
63152                 featuresByCode[id] = feature;
63153               }
63154             }
63155
63156             if (feature.properties.aliases) {
63157               for (var j in feature.properties.aliases) {
63158                 var alias = feature.properties.aliases[j].replace(idFilterRegex, '').toUpperCase();
63159                 featuresByCode[alias] = feature;
63160               }
63161             }
63162           }
63163         }
63164
63165         function locArray(loc) {
63166           if (Array.isArray(loc)) {
63167             return loc;
63168           } else if (loc.coordinates) {
63169             return loc.coordinates;
63170           }
63171
63172           return loc.geometry.coordinates;
63173         }
63174
63175         function smallestFeature(loc) {
63176           var query = locArray(loc);
63177           var featureProperties = whichPolygonGetter(query);
63178           if (!featureProperties) return null;
63179           return featuresByCode[featureProperties.id];
63180         }
63181
63182         function countryFeature(loc) {
63183           var feature = smallestFeature(loc);
63184           if (!feature) return null;
63185           var countryCode = feature.properties.country || feature.properties.iso1A2;
63186           return featuresByCode[countryCode];
63187         }
63188
63189         function featureForLoc(loc, opts) {
63190           if (opts && opts.level && opts.level !== 'country') {
63191             var features = featuresContaining(loc);
63192             var targetLevel = opts.level;
63193             var targetLevelIndex = levels.indexOf(targetLevel);
63194             if (targetLevelIndex === -1) return null;
63195
63196             for (var i in features) {
63197               var _feature3 = features[i];
63198
63199               if (_feature3.properties.level === targetLevel || levels.indexOf(_feature3.properties.level) > targetLevelIndex) {
63200                 return _feature3;
63201               }
63202             }
63203
63204             return null;
63205           }
63206
63207           return countryFeature(loc);
63208         }
63209
63210         function featureForID(id) {
63211           var stringID;
63212
63213           if (typeof id === 'number') {
63214             stringID = id.toString();
63215
63216             if (stringID.length === 1) {
63217               stringID = '00' + stringID;
63218             } else if (stringID.length === 2) {
63219               stringID = '0' + stringID;
63220             }
63221           } else {
63222             stringID = id.replace(idFilterRegex, '').toUpperCase();
63223           }
63224
63225           return featuresByCode[stringID] || null;
63226         }
63227
63228         function smallestOrMatchingFeature(query) {
63229           if (_typeof(query) === 'object') {
63230             return smallestFeature(query);
63231           }
63232
63233           return featureForID(query);
63234         }
63235
63236         function feature(query, opts) {
63237           if (_typeof(query) === 'object') {
63238             return featureForLoc(query, opts);
63239           }
63240
63241           return featureForID(query);
63242         }
63243         function iso1A2Code(query, opts) {
63244           var match = feature(query, opts);
63245           if (!match) return null;
63246           return match.properties.iso1A2 || null;
63247         }
63248         function featuresContaining(query, strict) {
63249           var feature = smallestOrMatchingFeature(query);
63250           if (!feature) return [];
63251           var features = [];
63252
63253           if (!strict || _typeof(query) === 'object') {
63254             features.push(feature);
63255           }
63256
63257           var properties = feature.properties;
63258
63259           for (var i in properties.groups) {
63260             var groupID = properties.groups[i];
63261             features.push(featuresByCode[groupID]);
63262           }
63263
63264           return features;
63265         }
63266         function roadSpeedUnit(query) {
63267           var feature = smallestOrMatchingFeature(query);
63268           return feature && feature.properties.roadSpeedUnit || null;
63269         }
63270
63271         var _dataDeprecated;
63272
63273         var _nsi;
63274
63275         function validationOutdatedTags() {
63276           var type = 'outdated_tags';
63277           var nsiKeys = ['amenity', 'shop', 'tourism', 'leisure', 'office']; // A concern here in switching to async data means that `_dataDeprecated`
63278           // and `_nsi` will not be available at first, so the data on early tiles
63279           // may not have tags validated fully.
63280           // initialize deprecated tags array
63281
63282           _mainFileFetcher.get('deprecated').then(function (d) {
63283             return _dataDeprecated = d;
63284           })["catch"](function () {
63285             /* ignore */
63286           });
63287           _mainFileFetcher.get('nsi_brands').then(function (d) {
63288             _nsi = {
63289               brands: d.brands,
63290               matcher: matcher$1(),
63291               wikidata: {},
63292               wikipedia: {}
63293             }; // initialize name-suggestion-index matcher
63294
63295             _nsi.matcher.buildMatchIndex(d.brands); // index all known wikipedia and wikidata tags
63296
63297
63298             Object.keys(d.brands).forEach(function (kvnd) {
63299               var brand = d.brands[kvnd];
63300               var wd = brand.tags['brand:wikidata'];
63301               var wp = brand.tags['brand:wikipedia'];
63302
63303               if (wd) {
63304                 _nsi.wikidata[wd] = kvnd;
63305               }
63306
63307               if (wp) {
63308                 _nsi.wikipedia[wp] = kvnd;
63309               }
63310             });
63311             return _nsi;
63312           })["catch"](function () {
63313             /* ignore */
63314           });
63315
63316           function oldTagIssues(entity, graph) {
63317             var oldTags = Object.assign({}, entity.tags); // shallow copy
63318
63319             var preset = _mainPresetIndex.match(entity, graph);
63320             var subtype = 'deprecated_tags';
63321             if (!preset) return []; // upgrade preset..
63322
63323             if (preset.replacement) {
63324               var newPreset = _mainPresetIndex.item(preset.replacement);
63325               graph = actionChangePreset(entity.id, preset, newPreset, true
63326               /* skip field defaults */
63327               )(graph);
63328               entity = graph.entity(entity.id);
63329               preset = newPreset;
63330             } // upgrade tags..
63331
63332
63333             if (_dataDeprecated) {
63334               var deprecatedTags = entity.deprecatedTags(_dataDeprecated);
63335
63336               if (deprecatedTags.length) {
63337                 deprecatedTags.forEach(function (tag) {
63338                   graph = actionUpgradeTags(entity.id, tag.old, tag.replace)(graph);
63339                 });
63340                 entity = graph.entity(entity.id);
63341               }
63342             } // add missing addTags..
63343
63344
63345             var newTags = Object.assign({}, entity.tags); // shallow copy
63346
63347             if (preset.tags !== preset.addTags) {
63348               Object.keys(preset.addTags).forEach(function (k) {
63349                 if (!newTags[k]) {
63350                   if (preset.addTags[k] === '*') {
63351                     newTags[k] = 'yes';
63352                   } else {
63353                     newTags[k] = preset.addTags[k];
63354                   }
63355                 }
63356               });
63357             }
63358
63359             if (_nsi) {
63360               // Do `wikidata` or `wikipedia` identify this entity as a brand?  #6416
63361               // If so, these tags can be swapped to `brand:wikidata`/`brand:wikipedia`
63362               var isBrand;
63363
63364               if (newTags.wikidata) {
63365                 // try matching `wikidata`
63366                 isBrand = _nsi.wikidata[newTags.wikidata];
63367               }
63368
63369               if (!isBrand && newTags.wikipedia) {
63370                 // fallback to `wikipedia`
63371                 isBrand = _nsi.wikipedia[newTags.wikipedia];
63372               }
63373
63374               if (isBrand && !newTags.office) {
63375                 // but avoid doing this for corporate offices
63376                 if (newTags.wikidata) {
63377                   newTags['brand:wikidata'] = newTags.wikidata;
63378                   delete newTags.wikidata;
63379                 }
63380
63381                 if (newTags.wikipedia) {
63382                   newTags['brand:wikipedia'] = newTags.wikipedia;
63383                   delete newTags.wikipedia;
63384                 } // I considered setting `name` and other tags here, but they aren't unique per wikidata
63385                 // (Q2759586 -> in USA "Papa John's", in Russia "Папа Джонс")
63386                 // So users will really need to use a preset or assign `name` themselves.
63387
63388               } // try key/value|name match against name-suggestion-index
63389
63390
63391               if (newTags.name) {
63392                 for (var i = 0; i < nsiKeys.length; i++) {
63393                   var k = nsiKeys[i];
63394                   if (!newTags[k]) continue;
63395                   var center = entity.extent(graph).center();
63396                   var countryCode = iso1A2Code(center);
63397
63398                   var match = _nsi.matcher.matchKVN(k, newTags[k], newTags.name, countryCode && countryCode.toLowerCase());
63399
63400                   if (!match) continue; // for now skip ambiguous matches (like Target~(USA) vs Target~(Australia))
63401
63402                   if (match.d) continue;
63403                   var brand = _nsi.brands[match.kvnd];
63404
63405                   if (brand && brand.tags['brand:wikidata'] && brand.tags['brand:wikidata'] !== entity.tags['not:brand:wikidata']) {
63406                     subtype = 'noncanonical_brand';
63407                     var keepTags = ['takeaway'].reduce(function (acc, k) {
63408                       if (newTags[k]) {
63409                         acc[k] = newTags[k];
63410                       }
63411
63412                       return acc;
63413                     }, {});
63414                     nsiKeys.forEach(function (k) {
63415                       return delete newTags[k];
63416                     });
63417                     Object.assign(newTags, brand.tags, keepTags);
63418                     break;
63419                   }
63420                 }
63421               }
63422             } // determine diff
63423
63424
63425             var tagDiff = utilTagDiff(oldTags, newTags);
63426             if (!tagDiff.length) return [];
63427             var isOnlyAddingTags = tagDiff.every(function (d) {
63428               return d.type === '+';
63429             });
63430             var prefix = '';
63431
63432             if (subtype === 'noncanonical_brand') {
63433               prefix = 'noncanonical_brand.';
63434             } else if (subtype === 'deprecated_tags' && isOnlyAddingTags) {
63435               subtype = 'incomplete_tags';
63436               prefix = 'incomplete.';
63437             } // don't allow autofixing brand tags
63438
63439
63440             var autoArgs = subtype !== 'noncanonical_brand' ? [doUpgrade, _t('issues.fix.upgrade_tags.annotation')] : null;
63441             return [new validationIssue({
63442               type: type,
63443               subtype: subtype,
63444               severity: 'warning',
63445               message: showMessage,
63446               reference: showReference,
63447               entityIds: [entity.id],
63448               hash: JSON.stringify(tagDiff),
63449               dynamicFixes: function dynamicFixes() {
63450                 return [new validationIssueFix({
63451                   autoArgs: autoArgs,
63452                   title: _t.html('issues.fix.upgrade_tags.title'),
63453                   onClick: function onClick(context) {
63454                     context.perform(doUpgrade, _t('issues.fix.upgrade_tags.annotation'));
63455                   }
63456                 })];
63457               }
63458             })];
63459
63460             function doUpgrade(graph) {
63461               var currEntity = graph.hasEntity(entity.id);
63462               if (!currEntity) return graph;
63463               var newTags = Object.assign({}, currEntity.tags); // shallow copy
63464
63465               tagDiff.forEach(function (diff) {
63466                 if (diff.type === '-') {
63467                   delete newTags[diff.key];
63468                 } else if (diff.type === '+') {
63469                   newTags[diff.key] = diff.newVal;
63470                 }
63471               });
63472               return actionChangeTags(currEntity.id, newTags)(graph);
63473             }
63474
63475             function showMessage(context) {
63476               var currEntity = context.hasEntity(entity.id);
63477               if (!currEntity) return '';
63478               var messageID = "issues.outdated_tags.".concat(prefix, "message");
63479
63480               if (subtype === 'noncanonical_brand' && isOnlyAddingTags) {
63481                 messageID += '_incomplete';
63482               }
63483
63484               return _t.html(messageID, {
63485                 feature: utilDisplayLabel(currEntity, context.graph())
63486               });
63487             }
63488
63489             function showReference(selection) {
63490               var enter = selection.selectAll('.issue-reference').data([0]).enter();
63491               enter.append('div').attr('class', 'issue-reference').html(_t.html("issues.outdated_tags.".concat(prefix, "reference")));
63492               enter.append('strong').html(_t.html('issues.suggested'));
63493               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) {
63494                 var klass = d.type === '+' ? 'add' : 'remove';
63495                 return "tagDiff-cell tagDiff-cell-".concat(klass);
63496               }).html(function (d) {
63497                 return d.display;
63498               });
63499             }
63500           }
63501
63502           function oldMultipolygonIssues(entity, graph) {
63503             var multipolygon, outerWay;
63504
63505             if (entity.type === 'relation') {
63506               outerWay = osmOldMultipolygonOuterMemberOfRelation(entity, graph);
63507               multipolygon = entity;
63508             } else if (entity.type === 'way') {
63509               multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
63510               outerWay = entity;
63511             } else {
63512               return [];
63513             }
63514
63515             if (!multipolygon || !outerWay) return [];
63516             return [new validationIssue({
63517               type: type,
63518               subtype: 'old_multipolygon',
63519               severity: 'warning',
63520               message: showMessage,
63521               reference: showReference,
63522               entityIds: [outerWay.id, multipolygon.id],
63523               dynamicFixes: function dynamicFixes() {
63524                 return [new validationIssueFix({
63525                   autoArgs: [doUpgrade, _t('issues.fix.move_tags.annotation')],
63526                   title: _t.html('issues.fix.move_tags.title'),
63527                   onClick: function onClick(context) {
63528                     context.perform(doUpgrade, _t('issues.fix.move_tags.annotation'));
63529                   }
63530                 })];
63531               }
63532             })];
63533
63534             function doUpgrade(graph) {
63535               var currMultipolygon = graph.hasEntity(multipolygon.id);
63536               var currOuterWay = graph.hasEntity(outerWay.id);
63537               if (!currMultipolygon || !currOuterWay) return graph;
63538               currMultipolygon = currMultipolygon.mergeTags(currOuterWay.tags);
63539               graph = graph.replace(currMultipolygon);
63540               return actionChangeTags(currOuterWay.id, {})(graph);
63541             }
63542
63543             function showMessage(context) {
63544               var currMultipolygon = context.hasEntity(multipolygon.id);
63545               if (!currMultipolygon) return '';
63546               return _t.html('issues.old_multipolygon.message', {
63547                 multipolygon: utilDisplayLabel(currMultipolygon, context.graph())
63548               });
63549             }
63550
63551             function showReference(selection) {
63552               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.old_multipolygon.reference'));
63553             }
63554           }
63555
63556           var validation = function checkOutdatedTags(entity, graph) {
63557             var issues = oldMultipolygonIssues(entity, graph);
63558             if (!issues.length) issues = oldTagIssues(entity, graph);
63559             return issues;
63560           };
63561
63562           validation.type = type;
63563           return validation;
63564         }
63565
63566         function validationPrivateData() {
63567           var type = 'private_data'; // assume that some buildings are private
63568
63569           var privateBuildingValues = {
63570             detached: true,
63571             farm: true,
63572             house: true,
63573             houseboat: true,
63574             residential: true,
63575             semidetached_house: true,
63576             static_caravan: true
63577           }; // but they might be public if they have one of these other tags
63578
63579           var publicKeys = {
63580             amenity: true,
63581             craft: true,
63582             historic: true,
63583             leisure: true,
63584             office: true,
63585             shop: true,
63586             tourism: true
63587           }; // these tags may contain personally identifying info
63588
63589           var personalTags = {
63590             'contact:email': true,
63591             'contact:fax': true,
63592             'contact:phone': true,
63593             email: true,
63594             fax: true,
63595             phone: true
63596           };
63597
63598           var validation = function checkPrivateData(entity) {
63599             var tags = entity.tags;
63600             if (!tags.building || !privateBuildingValues[tags.building]) return [];
63601             var keepTags = {};
63602
63603             for (var k in tags) {
63604               if (publicKeys[k]) return []; // probably a public feature
63605
63606               if (!personalTags[k]) {
63607                 keepTags[k] = tags[k];
63608               }
63609             }
63610
63611             var tagDiff = utilTagDiff(tags, keepTags);
63612             if (!tagDiff.length) return [];
63613             var fixID = tagDiff.length === 1 ? 'remove_tag' : 'remove_tags';
63614             return [new validationIssue({
63615               type: type,
63616               severity: 'warning',
63617               message: showMessage,
63618               reference: showReference,
63619               entityIds: [entity.id],
63620               dynamicFixes: function dynamicFixes() {
63621                 return [new validationIssueFix({
63622                   icon: 'iD-operation-delete',
63623                   title: _t.html('issues.fix.' + fixID + '.title'),
63624                   onClick: function onClick(context) {
63625                     context.perform(doUpgrade, _t('issues.fix.upgrade_tags.annotation'));
63626                   }
63627                 })];
63628               }
63629             })];
63630
63631             function doUpgrade(graph) {
63632               var currEntity = graph.hasEntity(entity.id);
63633               if (!currEntity) return graph;
63634               var newTags = Object.assign({}, currEntity.tags); // shallow copy
63635
63636               tagDiff.forEach(function (diff) {
63637                 if (diff.type === '-') {
63638                   delete newTags[diff.key];
63639                 } else if (diff.type === '+') {
63640                   newTags[diff.key] = diff.newVal;
63641                 }
63642               });
63643               return actionChangeTags(currEntity.id, newTags)(graph);
63644             }
63645
63646             function showMessage(context) {
63647               var currEntity = context.hasEntity(this.entityIds[0]);
63648               if (!currEntity) return '';
63649               return _t.html('issues.private_data.contact.message', {
63650                 feature: utilDisplayLabel(currEntity, context.graph())
63651               });
63652             }
63653
63654             function showReference(selection) {
63655               var enter = selection.selectAll('.issue-reference').data([0]).enter();
63656               enter.append('div').attr('class', 'issue-reference').html(_t.html('issues.private_data.reference'));
63657               enter.append('strong').html(_t.html('issues.suggested'));
63658               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) {
63659                 var klass = d.type === '+' ? 'add' : 'remove';
63660                 return 'tagDiff-cell tagDiff-cell-' + klass;
63661               }).html(function (d) {
63662                 return d.display;
63663               });
63664             }
63665           };
63666
63667           validation.type = type;
63668           return validation;
63669         }
63670
63671         var _discardNameRegexes = [];
63672         function validationSuspiciousName() {
63673           var type = 'suspicious_name';
63674           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
63675           // be available at first, so the data on early tiles may not have tags validated fully.
63676
63677           _mainFileFetcher.get('nsi_filters').then(function (filters) {
63678             // known list of generic names (e.g. "bar")
63679             _discardNameRegexes = filters.discardNames.map(function (discardName) {
63680               return new RegExp(discardName, 'i');
63681             });
63682           })["catch"](function () {
63683             /* ignore */
63684           });
63685
63686           function isDiscardedSuggestionName(lowercaseName) {
63687             return _discardNameRegexes.some(function (regex) {
63688               return regex.test(lowercaseName);
63689             });
63690           } // test if the name is just the key or tag value (e.g. "park")
63691
63692
63693           function nameMatchesRawTag(lowercaseName, tags) {
63694             for (var i = 0; i < keysToTestForGenericValues.length; i++) {
63695               var key = keysToTestForGenericValues[i];
63696               var val = tags[key];
63697
63698               if (val) {
63699                 val = val.toLowerCase();
63700
63701                 if (key === lowercaseName || val === lowercaseName || key.replace(/\_/g, ' ') === lowercaseName || val.replace(/\_/g, ' ') === lowercaseName) {
63702                   return true;
63703                 }
63704               }
63705             }
63706
63707             return false;
63708           }
63709
63710           function isGenericName(name, tags) {
63711             name = name.toLowerCase();
63712             return nameMatchesRawTag(name, tags) || isDiscardedSuggestionName(name);
63713           }
63714
63715           function makeGenericNameIssue(entityId, nameKey, genericName, langCode) {
63716             return new validationIssue({
63717               type: type,
63718               subtype: 'generic_name',
63719               severity: 'warning',
63720               message: function message(context) {
63721                 var entity = context.hasEntity(this.entityIds[0]);
63722                 if (!entity) return '';
63723                 var preset = _mainPresetIndex.match(entity, context.graph());
63724                 var langName = langCode && _mainLocalizer.languageName(langCode);
63725                 return _t.html('issues.generic_name.message' + (langName ? '_language' : ''), {
63726                   feature: preset.name(),
63727                   name: genericName,
63728                   language: langName
63729                 });
63730               },
63731               reference: showReference,
63732               entityIds: [entityId],
63733               hash: nameKey + '=' + genericName,
63734               dynamicFixes: function dynamicFixes() {
63735                 return [new validationIssueFix({
63736                   icon: 'iD-operation-delete',
63737                   title: _t.html('issues.fix.remove_the_name.title'),
63738                   onClick: function onClick(context) {
63739                     var entityId = this.issue.entityIds[0];
63740                     var entity = context.entity(entityId);
63741                     var tags = Object.assign({}, entity.tags); // shallow copy
63742
63743                     delete tags[nameKey];
63744                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_generic_name.annotation'));
63745                   }
63746                 })];
63747               }
63748             });
63749
63750             function showReference(selection) {
63751               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.generic_name.reference'));
63752             }
63753           }
63754
63755           function makeIncorrectNameIssue(entityId, nameKey, incorrectName, langCode) {
63756             return new validationIssue({
63757               type: type,
63758               subtype: 'not_name',
63759               severity: 'warning',
63760               message: function message(context) {
63761                 var entity = context.hasEntity(this.entityIds[0]);
63762                 if (!entity) return '';
63763                 var preset = _mainPresetIndex.match(entity, context.graph());
63764                 var langName = langCode && _mainLocalizer.languageName(langCode);
63765                 return _t.html('issues.incorrect_name.message' + (langName ? '_language' : ''), {
63766                   feature: preset.name(),
63767                   name: incorrectName,
63768                   language: langName
63769                 });
63770               },
63771               reference: showReference,
63772               entityIds: [entityId],
63773               hash: nameKey + '=' + incorrectName,
63774               dynamicFixes: function dynamicFixes() {
63775                 return [new validationIssueFix({
63776                   icon: 'iD-operation-delete',
63777                   title: _t.html('issues.fix.remove_the_name.title'),
63778                   onClick: function onClick(context) {
63779                     var entityId = this.issue.entityIds[0];
63780                     var entity = context.entity(entityId);
63781                     var tags = Object.assign({}, entity.tags); // shallow copy
63782
63783                     delete tags[nameKey];
63784                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_mistaken_name.annotation'));
63785                   }
63786                 })];
63787               }
63788             });
63789
63790             function showReference(selection) {
63791               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.generic_name.reference'));
63792             }
63793           }
63794
63795           var validation = function checkGenericName(entity) {
63796             // a generic name is okay if it's a known brand or entity
63797             if (entity.hasWikidata()) return [];
63798             var issues = [];
63799             var notNames = (entity.tags['not:name'] || '').split(';');
63800
63801             for (var key in entity.tags) {
63802               var m = key.match(/^name(?:(?::)([a-zA-Z_-]+))?$/);
63803               if (!m) continue;
63804               var langCode = m.length >= 2 ? m[1] : null;
63805               var value = entity.tags[key];
63806
63807               if (notNames.length) {
63808                 for (var i in notNames) {
63809                   var notName = notNames[i];
63810
63811                   if (notName && value === notName) {
63812                     issues.push(makeIncorrectNameIssue(entity.id, key, value, langCode));
63813                     continue;
63814                   }
63815                 }
63816               }
63817
63818               if (isGenericName(value, entity.tags)) {
63819                 issues.push(makeGenericNameIssue(entity.id, key, value, langCode));
63820               }
63821             }
63822
63823             return issues;
63824           };
63825
63826           validation.type = type;
63827           return validation;
63828         }
63829
63830         function validationUnsquareWay(context) {
63831           var type = 'unsquare_way';
63832           var DEFAULT_DEG_THRESHOLD = 5; // see also issues.js
63833           // use looser epsilon for detection to reduce warnings of buildings that are essentially square already
63834
63835           var epsilon = 0.05;
63836           var nodeThreshold = 10;
63837
63838           function isBuilding(entity, graph) {
63839             if (entity.type !== 'way' || entity.geometry(graph) !== 'area') return false;
63840             return entity.tags.building && entity.tags.building !== 'no';
63841           }
63842
63843           var validation = function checkUnsquareWay(entity, graph) {
63844             if (!isBuilding(entity, graph)) return []; // don't flag ways marked as physically unsquare
63845
63846             if (entity.tags.nonsquare === 'yes') return [];
63847             var isClosed = entity.isClosed();
63848             if (!isClosed) return []; // this building has bigger problems
63849             // don't flag ways with lots of nodes since they are likely detail-mapped
63850
63851             var nodes = graph.childNodes(entity).slice(); // shallow copy
63852
63853             if (nodes.length > nodeThreshold + 1) return []; // +1 because closing node appears twice
63854             // ignore if not all nodes are fully downloaded
63855
63856             var osm = services.osm;
63857             if (!osm || nodes.some(function (node) {
63858               return !osm.isDataLoaded(node.loc);
63859             })) return []; // don't flag connected ways to avoid unresolvable unsquare loops
63860
63861             var hasConnectedSquarableWays = nodes.some(function (node) {
63862               return graph.parentWays(node).some(function (way) {
63863                 if (way.id === entity.id) return false;
63864                 if (isBuilding(way, graph)) return true;
63865                 return graph.parentRelations(way).some(function (parentRelation) {
63866                   return parentRelation.isMultipolygon() && parentRelation.tags.building && parentRelation.tags.building !== 'no';
63867                 });
63868               });
63869             });
63870             if (hasConnectedSquarableWays) return []; // user-configurable square threshold
63871
63872             var storedDegreeThreshold = corePreferences('validate-square-degrees');
63873             var degreeThreshold = isNaN(storedDegreeThreshold) ? DEFAULT_DEG_THRESHOLD : parseFloat(storedDegreeThreshold);
63874             var points = nodes.map(function (node) {
63875               return context.projection(node.loc);
63876             });
63877             if (!geoOrthoCanOrthogonalize(points, isClosed, epsilon, degreeThreshold, true)) return [];
63878             var autoArgs; // don't allow autosquaring features linked to wikidata
63879
63880             if (!entity.tags.wikidata) {
63881               // use same degree threshold as for detection
63882               var autoAction = actionOrthogonalize(entity.id, context.projection, undefined, degreeThreshold);
63883               autoAction.transitionable = false; // when autofixing, do it instantly
63884
63885               autoArgs = [autoAction, _t('operations.orthogonalize.annotation.feature', {
63886                 n: 1
63887               })];
63888             }
63889
63890             return [new validationIssue({
63891               type: type,
63892               subtype: 'building',
63893               severity: 'warning',
63894               message: function message(context) {
63895                 var entity = context.hasEntity(this.entityIds[0]);
63896                 return entity ? _t.html('issues.unsquare_way.message', {
63897                   feature: utilDisplayLabel(entity, context.graph())
63898                 }) : '';
63899               },
63900               reference: showReference,
63901               entityIds: [entity.id],
63902               hash: JSON.stringify(autoArgs !== undefined) + degreeThreshold,
63903               dynamicFixes: function dynamicFixes() {
63904                 return [new validationIssueFix({
63905                   icon: 'iD-operation-orthogonalize',
63906                   title: _t.html('issues.fix.square_feature.title'),
63907                   autoArgs: autoArgs,
63908                   onClick: function onClick(context, completionHandler) {
63909                     var entityId = this.issue.entityIds[0]; // use same degree threshold as for detection
63910
63911                     context.perform(actionOrthogonalize(entityId, context.projection, undefined, degreeThreshold), _t('operations.orthogonalize.annotation.feature', {
63912                       n: 1
63913                     })); // run after the squaring transition (currently 150ms)
63914
63915                     window.setTimeout(function () {
63916                       completionHandler();
63917                     }, 175);
63918                   }
63919                 })
63920                 /*
63921                 new validationIssueFix({
63922                     title: t.html('issues.fix.tag_as_unsquare.title'),
63923                     onClick: function(context) {
63924                         var entityId = this.issue.entityIds[0];
63925                         var entity = context.entity(entityId);
63926                         var tags = Object.assign({}, entity.tags);  // shallow copy
63927                         tags.nonsquare = 'yes';
63928                         context.perform(
63929                             actionChangeTags(entityId, tags),
63930                             t('issues.fix.tag_as_unsquare.annotation')
63931                         );
63932                     }
63933                 })
63934                 */
63935                 ];
63936               }
63937             })];
63938
63939             function showReference(selection) {
63940               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.unsquare_way.buildings.reference'));
63941             }
63942           };
63943
63944           validation.type = type;
63945           return validation;
63946         }
63947
63948         var Validations = /*#__PURE__*/Object.freeze({
63949                 __proto__: null,
63950                 validationAlmostJunction: validationAlmostJunction,
63951                 validationCloseNodes: validationCloseNodes,
63952                 validationCrossingWays: validationCrossingWays,
63953                 validationDisconnectedWay: validationDisconnectedWay,
63954                 validationFormatting: validationFormatting,
63955                 validationHelpRequest: validationHelpRequest,
63956                 validationImpossibleOneway: validationImpossibleOneway,
63957                 validationIncompatibleSource: validationIncompatibleSource,
63958                 validationMaprules: validationMaprules,
63959                 validationMismatchedGeometry: validationMismatchedGeometry,
63960                 validationMissingRole: validationMissingRole,
63961                 validationMissingTag: validationMissingTag,
63962                 validationOutdatedTags: validationOutdatedTags,
63963                 validationPrivateData: validationPrivateData,
63964                 validationSuspiciousName: validationSuspiciousName,
63965                 validationUnsquareWay: validationUnsquareWay
63966         });
63967
63968         function coreValidator(context) {
63969           var dispatch$1 = dispatch('validated', 'focusedIssue');
63970           var validator = utilRebind({}, dispatch$1, 'on');
63971           var _rules = {};
63972           var _disabledRules = {};
63973           var _ignoredIssueIDs = {}; // issue.id -> true
63974
63975           var _baseCache = validationCache(); // issues before any user edits
63976
63977
63978           var _headCache = validationCache(); // issues after all user edits
63979
63980
63981           var _validatedGraph = null;
63982
63983           var _deferred = new Set(); //
63984           // initialize the validator rulesets
63985           //
63986
63987
63988           validator.init = function () {
63989             Object.values(Validations).forEach(function (validation) {
63990               if (typeof validation !== 'function') return;
63991               var fn = validation(context);
63992               var key = fn.type;
63993               _rules[key] = fn;
63994             });
63995             var disabledRules = corePreferences('validate-disabledRules');
63996
63997             if (disabledRules) {
63998               disabledRules.split(',').forEach(function (key) {
63999                 _disabledRules[key] = true;
64000               });
64001             }
64002           };
64003
64004           function reset(resetIgnored) {
64005             Array.from(_deferred).forEach(function (handle) {
64006               window.cancelIdleCallback(handle);
64007
64008               _deferred["delete"](handle);
64009             }); // clear caches
64010
64011             if (resetIgnored) _ignoredIssueIDs = {};
64012             _baseCache = validationCache();
64013             _headCache = validationCache();
64014             _validatedGraph = null;
64015           } //
64016           // clear caches, called whenever iD resets after a save
64017           //
64018
64019
64020           validator.reset = function () {
64021             reset(true);
64022           };
64023
64024           validator.resetIgnoredIssues = function () {
64025             _ignoredIssueIDs = {}; // reload UI
64026
64027             dispatch$1.call('validated');
64028           }; // must update issues when the user changes the unsquare thereshold
64029
64030
64031           validator.reloadUnsquareIssues = function () {
64032             reloadUnsquareIssues(_headCache, context.graph());
64033             reloadUnsquareIssues(_baseCache, context.history().base());
64034             dispatch$1.call('validated');
64035           };
64036
64037           function reloadUnsquareIssues(cache, graph) {
64038             var checkUnsquareWay = _rules.unsquare_way;
64039             if (typeof checkUnsquareWay !== 'function') return; // uncache existing
64040
64041             cache.uncacheIssuesOfType('unsquare_way');
64042             var buildings = context.history().tree().intersects(geoExtent([-180, -90], [180, 90]), graph) // everywhere
64043             .filter(function (entity) {
64044               return entity.type === 'way' && entity.tags.building && entity.tags.building !== 'no';
64045             }); // rerun for all buildings
64046
64047             buildings.forEach(function (entity) {
64048               var detected = checkUnsquareWay(entity, graph);
64049               if (detected.length !== 1) return;
64050               var issue = detected[0];
64051
64052               if (!cache.issuesByEntityID[entity.id]) {
64053                 cache.issuesByEntityID[entity.id] = new Set();
64054               }
64055
64056               cache.issuesByEntityID[entity.id].add(issue.id);
64057               cache.issuesByIssueID[issue.id] = issue;
64058             });
64059           } // options = {
64060           //     what: 'all',     // 'all' or 'edited'
64061           //     where: 'all',   // 'all' or 'visible'
64062           //     includeIgnored: false   // true, false, or 'only'
64063           //     includeDisabledRules: false   // true, false, or 'only'
64064           // };
64065
64066
64067           validator.getIssues = function (options) {
64068             var opts = Object.assign({
64069               what: 'all',
64070               where: 'all',
64071               includeIgnored: false,
64072               includeDisabledRules: false
64073             }, options);
64074             var issues = Object.values(_headCache.issuesByIssueID);
64075             var view = context.map().extent();
64076             return issues.filter(function (issue) {
64077               if (!issue) return false;
64078               if (opts.includeDisabledRules === 'only' && !_disabledRules[issue.type]) return false;
64079               if (!opts.includeDisabledRules && _disabledRules[issue.type]) return false;
64080               if (opts.includeIgnored === 'only' && !_ignoredIssueIDs[issue.id]) return false;
64081               if (!opts.includeIgnored && _ignoredIssueIDs[issue.id]) return false; // Sanity check:  This issue may be for an entity that not longer exists.
64082               // If we detect this, uncache and return false so it is not included..
64083
64084               var entityIds = issue.entityIds || [];
64085
64086               for (var i = 0; i < entityIds.length; i++) {
64087                 var entityId = entityIds[i];
64088
64089                 if (!context.hasEntity(entityId)) {
64090                   delete _headCache.issuesByEntityID[entityId];
64091                   delete _headCache.issuesByIssueID[issue.id];
64092                   return false;
64093                 }
64094               }
64095
64096               if (opts.what === 'edited' && _baseCache.issuesByIssueID[issue.id]) return false;
64097
64098               if (opts.where === 'visible') {
64099                 var extent = issue.extent(context.graph());
64100                 if (!view.intersects(extent)) return false;
64101               }
64102
64103               return true;
64104             });
64105           };
64106
64107           validator.getResolvedIssues = function () {
64108             var baseIssues = Object.values(_baseCache.issuesByIssueID);
64109             return baseIssues.filter(function (issue) {
64110               return !_headCache.issuesByIssueID[issue.id];
64111             });
64112           };
64113
64114           validator.focusIssue = function (issue) {
64115             var extent = issue.extent(context.graph());
64116
64117             if (extent) {
64118               var setZoom = Math.max(context.map().zoom(), 19);
64119               context.map().unobscuredCenterZoomEase(extent.center(), setZoom); // select the first entity
64120
64121               if (issue.entityIds && issue.entityIds.length) {
64122                 window.setTimeout(function () {
64123                   var ids = issue.entityIds;
64124                   context.enter(modeSelect(context, [ids[0]]));
64125                   dispatch$1.call('focusedIssue', this, issue);
64126                 }, 250); // after ease
64127               }
64128             }
64129           };
64130
64131           validator.getIssuesBySeverity = function (options) {
64132             var groups = utilArrayGroupBy(validator.getIssues(options), 'severity');
64133             groups.error = groups.error || [];
64134             groups.warning = groups.warning || [];
64135             return groups;
64136           }; // show some issue types in a particular order
64137
64138
64139           var orderedIssueTypes = [// flag missing data first
64140           'missing_tag', 'missing_role', // then flag identity issues
64141           'outdated_tags', 'mismatched_geometry', // flag geometry issues where fixing them might solve connectivity issues
64142           'crossing_ways', 'almost_junction', // then flag connectivity issues
64143           'disconnected_way', 'impossible_oneway']; // returns the issues that the given entity IDs have in common, matching the given options
64144
64145           validator.getSharedEntityIssues = function (entityIDs, options) {
64146             var cache = _headCache; // gather the issues that are common to all the entities
64147
64148             var issueIDs = entityIDs.reduce(function (acc, entityID) {
64149               var entityIssueIDs = cache.issuesByEntityID[entityID] || new Set();
64150
64151               if (!acc) {
64152                 return new Set(entityIssueIDs);
64153               }
64154
64155               return new Set(_toConsumableArray(acc).filter(function (elem) {
64156                 return entityIssueIDs.has(elem);
64157               }));
64158             }, null) || [];
64159             var opts = options || {};
64160             return Array.from(issueIDs).map(function (id) {
64161               return cache.issuesByIssueID[id];
64162             }).filter(function (issue) {
64163               if (!issue) return false;
64164               if (opts.includeDisabledRules === 'only' && !_disabledRules[issue.type]) return false;
64165               if (!opts.includeDisabledRules && _disabledRules[issue.type]) return false;
64166               if (opts.includeIgnored === 'only' && !_ignoredIssueIDs[issue.id]) return false;
64167               if (!opts.includeIgnored && _ignoredIssueIDs[issue.id]) return false;
64168               return true;
64169             }).sort(function (issue1, issue2) {
64170               if (issue1.type === issue2.type) {
64171                 // issues of the same type, sort deterministically
64172                 return issue1.id < issue2.id ? -1 : 1;
64173               }
64174
64175               var index1 = orderedIssueTypes.indexOf(issue1.type);
64176               var index2 = orderedIssueTypes.indexOf(issue2.type);
64177
64178               if (index1 !== -1 && index2 !== -1) {
64179                 // both issue types have explicit sort orders
64180                 return index1 - index2;
64181               } else if (index1 === -1 && index2 === -1) {
64182                 // neither issue type has an explicit sort order, sort by type
64183                 return issue1.type < issue2.type ? -1 : 1;
64184               } else {
64185                 // order explicit types before everything else
64186                 return index1 !== -1 ? -1 : 1;
64187               }
64188             });
64189           };
64190
64191           validator.getEntityIssues = function (entityID, options) {
64192             return validator.getSharedEntityIssues([entityID], options);
64193           };
64194
64195           validator.getRuleKeys = function () {
64196             return Object.keys(_rules);
64197           };
64198
64199           validator.isRuleEnabled = function (key) {
64200             return !_disabledRules[key];
64201           };
64202
64203           validator.toggleRule = function (key) {
64204             if (_disabledRules[key]) {
64205               delete _disabledRules[key];
64206             } else {
64207               _disabledRules[key] = true;
64208             }
64209
64210             corePreferences('validate-disabledRules', Object.keys(_disabledRules).join(','));
64211             validator.validate();
64212           };
64213
64214           validator.disableRules = function (keys) {
64215             _disabledRules = {};
64216             keys.forEach(function (k) {
64217               _disabledRules[k] = true;
64218             });
64219             corePreferences('validate-disabledRules', Object.keys(_disabledRules).join(','));
64220             validator.validate();
64221           };
64222
64223           validator.ignoreIssue = function (id) {
64224             _ignoredIssueIDs[id] = true;
64225           }; //
64226           // Run validation on a single entity for the given graph
64227           //
64228
64229
64230           function validateEntity(entity, graph) {
64231             var entityIssues = []; // runs validation and appends resulting issues
64232
64233             function runValidation(key) {
64234               var fn = _rules[key];
64235
64236               if (typeof fn !== 'function') {
64237                 console.error('no such validation rule = ' + key); // eslint-disable-line no-console
64238
64239                 return;
64240               }
64241
64242               var detected = fn(entity, graph);
64243               entityIssues = entityIssues.concat(detected);
64244             } // run all rules
64245
64246
64247             Object.keys(_rules).forEach(runValidation);
64248             return entityIssues;
64249           }
64250
64251           function entityIDsToValidate(entityIDs, graph) {
64252             var processedIDs = new Set();
64253             return entityIDs.reduce(function (acc, entityID) {
64254               // keep redundancy check separate from `acc` because an `entityID`
64255               // could have been added to `acc` as a related entity through an earlier pass
64256               if (processedIDs.has(entityID)) return acc;
64257               processedIDs.add(entityID);
64258               var entity = graph.hasEntity(entityID);
64259               if (!entity) return acc;
64260               acc.add(entityID);
64261               var checkParentRels = [entity];
64262
64263               if (entity.type === 'node') {
64264                 graph.parentWays(entity).forEach(function (parentWay) {
64265                   acc.add(parentWay.id); // include parent ways
64266
64267                   checkParentRels.push(parentWay);
64268                 });
64269               } else if (entity.type === 'relation') {
64270                 entity.members.forEach(function (member) {
64271                   acc.add(member.id); // include members
64272                 });
64273               } else if (entity.type === 'way') {
64274                 entity.nodes.forEach(function (nodeID) {
64275                   acc.add(nodeID); // include child nodes
64276
64277                   graph._parentWays[nodeID].forEach(function (wayID) {
64278                     acc.add(wayID); // include connected ways
64279                   });
64280                 });
64281               }
64282
64283               checkParentRels.forEach(function (entity) {
64284                 // include parent relations
64285                 if (entity.type !== 'relation') {
64286                   // but not super-relations
64287                   graph.parentRelations(entity).forEach(function (parentRelation) {
64288                     acc.add(parentRelation.id);
64289                   });
64290                 }
64291               });
64292               return acc;
64293             }, new Set());
64294           } //
64295           // Run validation for several entities, supplied `entityIDs`,
64296           // against `graph` for the given `cache`
64297           //
64298
64299
64300           function validateEntities(entityIDs, graph, cache) {
64301             // clear caches for existing issues related to these entities
64302             entityIDs.forEach(cache.uncacheEntityID); // detect new issues and update caches
64303
64304             entityIDs.forEach(function (entityID) {
64305               var entity = graph.hasEntity(entityID); // don't validate deleted entities
64306
64307               if (!entity) return;
64308               var issues = validateEntity(entity, graph);
64309               cache.cacheIssues(issues);
64310             });
64311           } //
64312           // Validates anything that has changed since the last time it was run.
64313           // Also updates the "validatedGraph" to be the current graph
64314           // and dispatches a `validated` event when finished.
64315           //
64316
64317
64318           validator.validate = function () {
64319             var currGraph = context.graph();
64320             _validatedGraph = _validatedGraph || context.history().base();
64321
64322             if (currGraph === _validatedGraph) {
64323               dispatch$1.call('validated');
64324               return;
64325             }
64326
64327             var oldGraph = _validatedGraph;
64328             var difference = coreDifference(oldGraph, currGraph);
64329             _validatedGraph = currGraph;
64330             var createdAndModifiedEntityIDs = difference.extantIDs(true); // created/modified (true = w/relation members)
64331
64332             var entityIDsToCheck = entityIDsToValidate(createdAndModifiedEntityIDs, currGraph); // check modified and deleted entities against the old graph in order to update their related entities
64333             // (e.g. deleting the only highway connected to a road should create a disconnected highway issue)
64334
64335             var modifiedAndDeletedEntityIDs = difference.deleted().concat(difference.modified()).map(function (entity) {
64336               return entity.id;
64337             });
64338             var entityIDsToCheckForOldGraph = entityIDsToValidate(modifiedAndDeletedEntityIDs, oldGraph); // concat the sets
64339
64340             entityIDsToCheckForOldGraph.forEach(entityIDsToCheck.add, entityIDsToCheck);
64341             validateEntities(entityIDsToCheck, context.graph(), _headCache);
64342             dispatch$1.call('validated');
64343           };
64344
64345           context.history().on('reset.validator', function () {
64346             // cached issues aren't valid any longer if the history has been reset
64347             reset(false);
64348             validator.validate();
64349           }); // WHEN TO RUN VALIDATION:
64350           // When graph changes:
64351
64352           context.history().on('restore.validator', validator.validate) // restore saved history
64353           .on('undone.validator', validator.validate) // undo
64354           .on('redone.validator', validator.validate); // redo
64355           // but not on 'change' (e.g. while drawing)
64356           // When user changes editing modes:
64357
64358           context.on('exit.validator', validator.validate); // When merging fetched data:
64359
64360           context.history().on('merge.validator', function (entities) {
64361             if (!entities) return;
64362             var handle = window.requestIdleCallback(function () {
64363               var entityIDs = entities.map(function (entity) {
64364                 return entity.id;
64365               });
64366               var headGraph = context.graph();
64367               validateEntities(entityIDsToValidate(entityIDs, headGraph), headGraph, _headCache);
64368               var baseGraph = context.history().base();
64369               validateEntities(entityIDsToValidate(entityIDs, baseGraph), baseGraph, _baseCache);
64370               dispatch$1.call('validated');
64371             });
64372
64373             _deferred.add(handle);
64374           });
64375           return validator;
64376         }
64377
64378         function validationCache() {
64379           var cache = {
64380             issuesByIssueID: {},
64381             // issue.id -> issue
64382             issuesByEntityID: {} // entity.id -> set(issue.id)
64383
64384           };
64385
64386           cache.cacheIssues = function (issues) {
64387             issues.forEach(function (issue) {
64388               var entityIds = issue.entityIds || [];
64389               entityIds.forEach(function (entityId) {
64390                 if (!cache.issuesByEntityID[entityId]) {
64391                   cache.issuesByEntityID[entityId] = new Set();
64392                 }
64393
64394                 cache.issuesByEntityID[entityId].add(issue.id);
64395               });
64396               cache.issuesByIssueID[issue.id] = issue;
64397             });
64398           };
64399
64400           cache.uncacheIssue = function (issue) {
64401             // When multiple entities are involved (e.g. crossing_ways),
64402             // remove this issue from the other entity caches too..
64403             var entityIds = issue.entityIds || [];
64404             entityIds.forEach(function (entityId) {
64405               if (cache.issuesByEntityID[entityId]) {
64406                 cache.issuesByEntityID[entityId]["delete"](issue.id);
64407               }
64408             });
64409             delete cache.issuesByIssueID[issue.id];
64410           };
64411
64412           cache.uncacheIssues = function (issues) {
64413             issues.forEach(cache.uncacheIssue);
64414           };
64415
64416           cache.uncacheIssuesOfType = function (type) {
64417             var issuesOfType = Object.values(cache.issuesByIssueID).filter(function (issue) {
64418               return issue.type === type;
64419             });
64420             cache.uncacheIssues(issuesOfType);
64421           }; //
64422           // Remove a single entity and all its related issues from the caches
64423           //
64424
64425
64426           cache.uncacheEntityID = function (entityID) {
64427             var issueIDs = cache.issuesByEntityID[entityID];
64428             if (!issueIDs) return;
64429             issueIDs.forEach(function (issueID) {
64430               var issue = cache.issuesByIssueID[issueID];
64431
64432               if (issue) {
64433                 cache.uncacheIssue(issue);
64434               } else {
64435                 delete cache.issuesByIssueID[issueID];
64436               }
64437             });
64438             delete cache.issuesByEntityID[entityID];
64439           };
64440
64441           return cache;
64442         }
64443
64444         function coreUploader(context) {
64445           var dispatch$1 = dispatch( // Start and end events are dispatched exactly once each per legitimate outside call to `save`
64446           'saveStarted', // dispatched as soon as a call to `save` has been deemed legitimate
64447           'saveEnded', // dispatched after the result event has been dispatched
64448           'willAttemptUpload', // dispatched before the actual upload call occurs, if it will
64449           'progressChanged', // Each save results in one of these outcomes:
64450           'resultNoChanges', // upload wasn't attempted since there were no edits
64451           'resultErrors', // upload failed due to errors
64452           'resultConflicts', // upload failed due to data conflicts
64453           'resultSuccess' // upload completed without errors
64454           );
64455           var _isSaving = false;
64456           var _conflicts = [];
64457           var _errors = [];
64458
64459           var _origChanges;
64460
64461           var _discardTags = {};
64462           _mainFileFetcher.get('discarded').then(function (d) {
64463             _discardTags = d;
64464           })["catch"](function () {
64465             /* ignore */
64466           });
64467           var uploader = utilRebind({}, dispatch$1, 'on');
64468
64469           uploader.isSaving = function () {
64470             return _isSaving;
64471           };
64472
64473           uploader.save = function (changeset, tryAgain, checkConflicts) {
64474             // Guard against accidentally entering save code twice - #4641
64475             if (_isSaving && !tryAgain) {
64476               return;
64477             }
64478
64479             var osm = context.connection();
64480             if (!osm) return; // If user somehow got logged out mid-save, try to reauthenticate..
64481             // This can happen if they were logged in from before, but the tokens are no longer valid.
64482
64483             if (!osm.authenticated()) {
64484               osm.authenticate(function (err) {
64485                 if (!err) {
64486                   uploader.save(changeset, tryAgain, checkConflicts); // continue where we left off..
64487                 }
64488               });
64489               return;
64490             }
64491
64492             if (!_isSaving) {
64493               _isSaving = true;
64494               dispatch$1.call('saveStarted', this);
64495             }
64496
64497             var history = context.history();
64498             _conflicts = [];
64499             _errors = []; // Store original changes, in case user wants to download them as an .osc file
64500
64501             _origChanges = history.changes(actionDiscardTags(history.difference(), _discardTags)); // First time, `history.perform` a no-op action.
64502             // Any conflict resolutions will be done as `history.replace`
64503             // Remember to pop this later if needed
64504
64505             if (!tryAgain) {
64506               history.perform(actionNoop());
64507             } // Attempt a fast upload.. If there are conflicts, re-enter with `checkConflicts = true`
64508
64509
64510             if (!checkConflicts) {
64511               upload(changeset); // Do the full (slow) conflict check..
64512             } else {
64513               performFullConflictCheck(changeset);
64514             }
64515           };
64516
64517           function performFullConflictCheck(changeset) {
64518             var osm = context.connection();
64519             if (!osm) return;
64520             var history = context.history();
64521             var localGraph = context.graph();
64522             var remoteGraph = coreGraph(history.base(), true);
64523             var summary = history.difference().summary();
64524             var _toCheck = [];
64525
64526             for (var i = 0; i < summary.length; i++) {
64527               var item = summary[i];
64528
64529               if (item.changeType === 'modified') {
64530                 _toCheck.push(item.entity.id);
64531               }
64532             }
64533
64534             var _toLoad = withChildNodes(_toCheck, localGraph);
64535
64536             var _loaded = {};
64537             var _toLoadCount = 0;
64538             var _toLoadTotal = _toLoad.length;
64539
64540             if (_toCheck.length) {
64541               dispatch$1.call('progressChanged', this, _toLoadCount, _toLoadTotal);
64542
64543               _toLoad.forEach(function (id) {
64544                 _loaded[id] = false;
64545               });
64546
64547               osm.loadMultiple(_toLoad, loaded);
64548             } else {
64549               upload(changeset);
64550             }
64551
64552             return;
64553
64554             function withChildNodes(ids, graph) {
64555               var s = new Set(ids);
64556               ids.forEach(function (id) {
64557                 var entity = graph.entity(id);
64558                 if (entity.type !== 'way') return;
64559                 graph.childNodes(entity).forEach(function (child) {
64560                   if (child.version !== undefined) {
64561                     s.add(child.id);
64562                   }
64563                 });
64564               });
64565               return Array.from(s);
64566             } // Reload modified entities into an alternate graph and check for conflicts..
64567
64568
64569             function loaded(err, result) {
64570               if (_errors.length) return;
64571
64572               if (err) {
64573                 _errors.push({
64574                   msg: err.message || err.responseText,
64575                   details: [_t('save.status_code', {
64576                     code: err.status
64577                   })]
64578                 });
64579
64580                 didResultInErrors();
64581               } else {
64582                 var loadMore = [];
64583                 result.data.forEach(function (entity) {
64584                   remoteGraph.replace(entity);
64585                   _loaded[entity.id] = true;
64586                   _toLoad = _toLoad.filter(function (val) {
64587                     return val !== entity.id;
64588                   });
64589                   if (!entity.visible) return; // Because loadMultiple doesn't download /full like loadEntity,
64590                   // need to also load children that aren't already being checked..
64591
64592                   var i, id;
64593
64594                   if (entity.type === 'way') {
64595                     for (i = 0; i < entity.nodes.length; i++) {
64596                       id = entity.nodes[i];
64597
64598                       if (_loaded[id] === undefined) {
64599                         _loaded[id] = false;
64600                         loadMore.push(id);
64601                       }
64602                     }
64603                   } else if (entity.type === 'relation' && entity.isMultipolygon()) {
64604                     for (i = 0; i < entity.members.length; i++) {
64605                       id = entity.members[i].id;
64606
64607                       if (_loaded[id] === undefined) {
64608                         _loaded[id] = false;
64609                         loadMore.push(id);
64610                       }
64611                     }
64612                   }
64613                 });
64614                 _toLoadCount += result.data.length;
64615                 _toLoadTotal += loadMore.length;
64616                 dispatch$1.call('progressChanged', this, _toLoadCount, _toLoadTotal);
64617
64618                 if (loadMore.length) {
64619                   _toLoad.push.apply(_toLoad, loadMore);
64620
64621                   osm.loadMultiple(loadMore, loaded);
64622                 }
64623
64624                 if (!_toLoad.length) {
64625                   detectConflicts();
64626                   upload(changeset);
64627                 }
64628               }
64629             }
64630
64631             function detectConflicts() {
64632               function choice(id, text, _action) {
64633                 return {
64634                   id: id,
64635                   text: text,
64636                   action: function action() {
64637                     history.replace(_action);
64638                   }
64639                 };
64640               }
64641
64642               function formatUser(d) {
64643                 return '<a href="' + osm.userURL(d) + '" target="_blank">' + d + '</a>';
64644               }
64645
64646               function entityName(entity) {
64647                 return utilDisplayName(entity) || utilDisplayType(entity.id) + ' ' + entity.id;
64648               }
64649
64650               function sameVersions(local, remote) {
64651                 if (local.version !== remote.version) return false;
64652
64653                 if (local.type === 'way') {
64654                   var children = utilArrayUnion(local.nodes, remote.nodes);
64655
64656                   for (var i = 0; i < children.length; i++) {
64657                     var a = localGraph.hasEntity(children[i]);
64658                     var b = remoteGraph.hasEntity(children[i]);
64659                     if (a && b && a.version !== b.version) return false;
64660                   }
64661                 }
64662
64663                 return true;
64664               }
64665
64666               _toCheck.forEach(function (id) {
64667                 var local = localGraph.entity(id);
64668                 var remote = remoteGraph.entity(id);
64669                 if (sameVersions(local, remote)) return;
64670                 var merge = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags, formatUser);
64671                 history.replace(merge);
64672                 var mergeConflicts = merge.conflicts();
64673                 if (!mergeConflicts.length) return; // merged safely
64674
64675                 var forceLocal = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags).withOption('force_local');
64676                 var forceRemote = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags).withOption('force_remote');
64677                 var keepMine = _t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore'));
64678                 var keepTheirs = _t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
64679
64680                 _conflicts.push({
64681                   id: id,
64682                   name: entityName(local),
64683                   details: mergeConflicts,
64684                   chosen: 1,
64685                   choices: [choice(id, keepMine, forceLocal), choice(id, keepTheirs, forceRemote)]
64686                 });
64687               });
64688             }
64689           }
64690
64691           function upload(changeset) {
64692             var osm = context.connection();
64693
64694             if (!osm) {
64695               _errors.push({
64696                 msg: 'No OSM Service'
64697               });
64698             }
64699
64700             if (_conflicts.length) {
64701               didResultInConflicts(changeset);
64702             } else if (_errors.length) {
64703               didResultInErrors();
64704             } else {
64705               var history = context.history();
64706               var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
64707
64708               if (changes.modified.length || changes.created.length || changes.deleted.length) {
64709                 dispatch$1.call('willAttemptUpload', this);
64710                 osm.putChangeset(changeset, changes, uploadCallback);
64711               } else {
64712                 // changes were insignificant or reverted by user
64713                 didResultInNoChanges();
64714               }
64715             }
64716           }
64717
64718           function uploadCallback(err, changeset) {
64719             if (err) {
64720               if (err.status === 409) {
64721                 // 409 Conflict
64722                 uploader.save(changeset, true, true); // tryAgain = true, checkConflicts = true
64723               } else {
64724                 _errors.push({
64725                   msg: err.message || err.responseText,
64726                   details: [_t('save.status_code', {
64727                     code: err.status
64728                   })]
64729                 });
64730
64731                 didResultInErrors();
64732               }
64733             } else {
64734               didResultInSuccess(changeset);
64735             }
64736           }
64737
64738           function didResultInNoChanges() {
64739             dispatch$1.call('resultNoChanges', this);
64740             endSave();
64741             context.flush(); // reset iD
64742           }
64743
64744           function didResultInErrors() {
64745             context.history().pop();
64746             dispatch$1.call('resultErrors', this, _errors);
64747             endSave();
64748           }
64749
64750           function didResultInConflicts(changeset) {
64751             _conflicts.sort(function (a, b) {
64752               return b.id.localeCompare(a.id);
64753             });
64754
64755             dispatch$1.call('resultConflicts', this, changeset, _conflicts, _origChanges);
64756             endSave();
64757           }
64758
64759           function didResultInSuccess(changeset) {
64760             // delete the edit stack cached to local storage
64761             context.history().clearSaved();
64762             dispatch$1.call('resultSuccess', this, changeset); // Add delay to allow for postgres replication #1646 #2678
64763
64764             window.setTimeout(function () {
64765               endSave();
64766               context.flush(); // reset iD
64767             }, 2500);
64768           }
64769
64770           function endSave() {
64771             _isSaving = false;
64772             dispatch$1.call('saveEnded', this);
64773           }
64774
64775           uploader.cancelConflictResolution = function () {
64776             context.history().pop();
64777           };
64778
64779           uploader.processResolvedConflicts = function (changeset) {
64780             var history = context.history();
64781
64782             for (var i = 0; i < _conflicts.length; i++) {
64783               if (_conflicts[i].chosen === 1) {
64784                 // user chose "use theirs"
64785                 var entity = context.hasEntity(_conflicts[i].id);
64786
64787                 if (entity && entity.type === 'way') {
64788                   var children = utilArrayUniq(entity.nodes);
64789
64790                   for (var j = 0; j < children.length; j++) {
64791                     history.replace(actionRevert(children[j]));
64792                   }
64793                 }
64794
64795                 history.replace(actionRevert(_conflicts[i].id));
64796               }
64797             }
64798
64799             uploader.save(changeset, true, false); // tryAgain = true, checkConflicts = false
64800           };
64801
64802           uploader.reset = function () {};
64803
64804           return uploader;
64805         }
64806
64807         var abs$4 = Math.abs;
64808         var exp$2 = Math.exp;
64809         var E = Math.E;
64810
64811         var FORCED$g = fails(function () {
64812           return Math.sinh(-2e-17) != -2e-17;
64813         });
64814
64815         // `Math.sinh` method
64816         // https://tc39.github.io/ecma262/#sec-math.sinh
64817         // V8 near Chromium 38 has a problem with very small numbers
64818         _export({ target: 'Math', stat: true, forced: FORCED$g }, {
64819           sinh: function sinh(x) {
64820             return abs$4(x = +x) < 1 ? (mathExpm1(x) - mathExpm1(-x)) / 2 : (exp$2(x - 1) - exp$2(-x - 1)) * (E / 2);
64821           }
64822         });
64823
64824         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
64825
64826         window.matchMedia("\n        (-webkit-min-device-pixel-ratio: 2), /* Safari */\n        (min-resolution: 2dppx),             /* standard */\n        (min-resolution: 192dpi)             /* fallback */\n    ").addListener(function () {
64827           isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
64828         });
64829
64830         function localeDateString(s) {
64831           if (!s) return null;
64832           var options = {
64833             day: 'numeric',
64834             month: 'short',
64835             year: 'numeric'
64836           };
64837           var d = new Date(s);
64838           if (isNaN(d.getTime())) return null;
64839           return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
64840         }
64841
64842         function vintageRange(vintage) {
64843           var s;
64844
64845           if (vintage.start || vintage.end) {
64846             s = vintage.start || '?';
64847
64848             if (vintage.start !== vintage.end) {
64849               s += ' - ' + (vintage.end || '?');
64850             }
64851           }
64852
64853           return s;
64854         }
64855
64856         function rendererBackgroundSource(data) {
64857           var source = Object.assign({}, data); // shallow copy
64858
64859           var _offset = [0, 0];
64860           var _name = source.name;
64861           var _description = source.description;
64862
64863           var _best = !!source.best;
64864
64865           var _template = source.encrypted ? utilAesDecrypt(source.template) : source.template;
64866
64867           source.tileSize = data.tileSize || 256;
64868           source.zoomExtent = data.zoomExtent || [0, 22];
64869           source.overzoom = data.overzoom !== false;
64870
64871           source.offset = function (val) {
64872             if (!arguments.length) return _offset;
64873             _offset = val;
64874             return source;
64875           };
64876
64877           source.nudge = function (val, zoomlevel) {
64878             _offset[0] += val[0] / Math.pow(2, zoomlevel);
64879             _offset[1] += val[1] / Math.pow(2, zoomlevel);
64880             return source;
64881           };
64882
64883           source.name = function () {
64884             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
64885             return _t('imagery.' + id_safe + '.name', {
64886               "default": _name
64887             });
64888           };
64889
64890           source.label = function () {
64891             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
64892             return _t.html('imagery.' + id_safe + '.name', {
64893               "default": _name
64894             });
64895           };
64896
64897           source.description = function () {
64898             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
64899             return _t.html('imagery.' + id_safe + '.description', {
64900               "default": _description
64901             });
64902           };
64903
64904           source.best = function () {
64905             return _best;
64906           };
64907
64908           source.area = function () {
64909             if (!data.polygon) return Number.MAX_VALUE; // worldwide
64910
64911             var area = d3_geoArea({
64912               type: 'MultiPolygon',
64913               coordinates: [data.polygon]
64914             });
64915             return isNaN(area) ? 0 : area;
64916           };
64917
64918           source.imageryUsed = function () {
64919             return _name || source.id;
64920           };
64921
64922           source.template = function (val) {
64923             if (!arguments.length) return _template;
64924
64925             if (source.id === 'custom') {
64926               _template = val;
64927             }
64928
64929             return source;
64930           };
64931
64932           source.url = function (coord) {
64933             var result = _template;
64934             if (result === '') return result; // source 'none'
64935             // Guess a type based on the tokens present in the template
64936             // (This is for 'custom' source, where we don't know)
64937
64938             if (!source.type) {
64939               if (/SERVICE=WMS|\{(proj|wkid|bbox)\}/.test(_template)) {
64940                 source.type = 'wms';
64941                 source.projection = 'EPSG:3857'; // guess
64942               } else if (/\{(x|y)\}/.test(_template)) {
64943                 source.type = 'tms';
64944               } else if (/\{u\}/.test(_template)) {
64945                 source.type = 'bing';
64946               }
64947             }
64948
64949             if (source.type === 'wms') {
64950               var tileToProjectedCoords = function tileToProjectedCoords(x, y, z) {
64951                 //polyfill for IE11, PhantomJS
64952                 var sinh = Math.sinh || function (x) {
64953                   var y = Math.exp(x);
64954                   return (y - 1 / y) / 2;
64955                 };
64956
64957                 var zoomSize = Math.pow(2, z);
64958                 var lon = x / zoomSize * Math.PI * 2 - Math.PI;
64959                 var lat = Math.atan(sinh(Math.PI * (1 - 2 * y / zoomSize)));
64960
64961                 switch (source.projection) {
64962                   case 'EPSG:4326':
64963                     return {
64964                       x: lon * 180 / Math.PI,
64965                       y: lat * 180 / Math.PI
64966                     };
64967
64968                   default:
64969                     // EPSG:3857 and synonyms
64970                     var mercCoords = mercatorRaw(lon, lat);
64971                     return {
64972                       x: 20037508.34 / Math.PI * mercCoords[0],
64973                       y: 20037508.34 / Math.PI * mercCoords[1]
64974                     };
64975                 }
64976               };
64977
64978               var tileSize = source.tileSize;
64979               var projection = source.projection;
64980               var minXmaxY = tileToProjectedCoords(coord[0], coord[1], coord[2]);
64981               var maxXminY = tileToProjectedCoords(coord[0] + 1, coord[1] + 1, coord[2]);
64982               result = result.replace(/\{(\w+)\}/g, function (token, key) {
64983                 switch (key) {
64984                   case 'width':
64985                   case 'height':
64986                     return tileSize;
64987
64988                   case 'proj':
64989                     return projection;
64990
64991                   case 'wkid':
64992                     return projection.replace(/^EPSG:/, '');
64993
64994                   case 'bbox':
64995                     // WMS 1.3 flips x/y for some coordinate systems including EPSG:4326 - #7557
64996                     if (projection === 'EPSG:4326' && // The CRS parameter implies version 1.3 (prior versions use SRS)
64997                     /VERSION=1.3|CRS={proj}/.test(source.template())) {
64998                       return maxXminY.y + ',' + minXmaxY.x + ',' + minXmaxY.y + ',' + maxXminY.x;
64999                     } else {
65000                       return minXmaxY.x + ',' + maxXminY.y + ',' + maxXminY.x + ',' + minXmaxY.y;
65001                     }
65002
65003                   case 'w':
65004                     return minXmaxY.x;
65005
65006                   case 's':
65007                     return maxXminY.y;
65008
65009                   case 'n':
65010                     return maxXminY.x;
65011
65012                   case 'e':
65013                     return minXmaxY.y;
65014
65015                   default:
65016                     return token;
65017                 }
65018               });
65019             } else if (source.type === 'tms') {
65020               result = result.replace('{x}', coord[0]).replace('{y}', coord[1]) // TMS-flipped y coordinate
65021               .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1).replace(/\{z(oom)?\}/, coord[2]) // only fetch retina tiles for retina screens
65022               .replace(/\{@2x\}|\{r\}/, isRetina ? '@2x' : '');
65023             } else if (source.type === 'bing') {
65024               result = result.replace('{u}', function () {
65025                 var u = '';
65026
65027                 for (var zoom = coord[2]; zoom > 0; zoom--) {
65028                   var b = 0;
65029                   var mask = 1 << zoom - 1;
65030                   if ((coord[0] & mask) !== 0) b++;
65031                   if ((coord[1] & mask) !== 0) b += 2;
65032                   u += b.toString();
65033                 }
65034
65035                 return u;
65036               });
65037             } // these apply to any type..
65038
65039
65040             result = result.replace(/\{switch:([^}]+)\}/, function (s, r) {
65041               var subdomains = r.split(',');
65042               return subdomains[(coord[0] + coord[1]) % subdomains.length];
65043             });
65044             return result;
65045           };
65046
65047           source.validZoom = function (z) {
65048             return source.zoomExtent[0] <= z && (source.overzoom || source.zoomExtent[1] > z);
65049           };
65050
65051           source.isLocatorOverlay = function () {
65052             return source.id === 'mapbox_locator_overlay';
65053           };
65054           /* hides a source from the list, but leaves it available for use */
65055
65056
65057           source.isHidden = function () {
65058             return source.id === 'DigitalGlobe-Premium-vintage' || source.id === 'DigitalGlobe-Standard-vintage';
65059           };
65060
65061           source.copyrightNotices = function () {};
65062
65063           source.getMetadata = function (center, tileCoord, callback) {
65064             var vintage = {
65065               start: localeDateString(source.startDate),
65066               end: localeDateString(source.endDate)
65067             };
65068             vintage.range = vintageRange(vintage);
65069             var metadata = {
65070               vintage: vintage
65071             };
65072             callback(null, metadata);
65073           };
65074
65075           return source;
65076         }
65077
65078         rendererBackgroundSource.Bing = function (data, dispatch) {
65079           // http://msdn.microsoft.com/en-us/library/ff701716.aspx
65080           // http://msdn.microsoft.com/en-us/library/ff701701.aspx
65081           data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
65082           var bing = rendererBackgroundSource(data); // var key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU'; // P2, JOSM, etc
65083
65084           var key = 'Ak5oTE46TUbjRp08OFVcGpkARErDobfpuyNKa-W2mQ8wbt1K1KL8p1bIRwWwcF-Q'; // iD
65085
65086           var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' + key;
65087           var cache = {};
65088           var inflight = {};
65089           var providers = [];
65090           d3_json(url).then(function (json) {
65091             providers = json.resourceSets[0].resources[0].imageryProviders.map(function (provider) {
65092               return {
65093                 attribution: provider.attribution,
65094                 areas: provider.coverageAreas.map(function (area) {
65095                   return {
65096                     zoom: [area.zoomMin, area.zoomMax],
65097                     extent: geoExtent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
65098                   };
65099                 })
65100               };
65101             });
65102             dispatch.call('change');
65103           })["catch"](function () {
65104             /* ignore */
65105           });
65106
65107           bing.copyrightNotices = function (zoom, extent) {
65108             zoom = Math.min(zoom, 21);
65109             return providers.filter(function (provider) {
65110               return provider.areas.some(function (area) {
65111                 return extent.intersects(area.extent) && area.zoom[0] <= zoom && area.zoom[1] >= zoom;
65112               });
65113             }).map(function (provider) {
65114               return provider.attribution;
65115             }).join(', ');
65116           };
65117
65118           bing.getMetadata = function (center, tileCoord, callback) {
65119             var tileID = tileCoord.slice(0, 3).join('/');
65120             var zoom = Math.min(tileCoord[2], 21);
65121             var centerPoint = center[1] + ',' + center[0]; // lat,lng
65122
65123             var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/' + centerPoint + '?zl=' + zoom + '&key=' + key;
65124             if (inflight[tileID]) return;
65125
65126             if (!cache[tileID]) {
65127               cache[tileID] = {};
65128             }
65129
65130             if (cache[tileID] && cache[tileID].metadata) {
65131               return callback(null, cache[tileID].metadata);
65132             }
65133
65134             inflight[tileID] = true;
65135             d3_json(url).then(function (result) {
65136               delete inflight[tileID];
65137
65138               if (!result) {
65139                 throw new Error('Unknown Error');
65140               }
65141
65142               var vintage = {
65143                 start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
65144                 end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
65145               };
65146               vintage.range = vintageRange(vintage);
65147               var metadata = {
65148                 vintage: vintage
65149               };
65150               cache[tileID].metadata = metadata;
65151               if (callback) callback(null, metadata);
65152             })["catch"](function (err) {
65153               delete inflight[tileID];
65154               if (callback) callback(err.message);
65155             });
65156           };
65157
65158           bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
65159           return bing;
65160         };
65161
65162         rendererBackgroundSource.Esri = function (data) {
65163           // in addition to using the tilemap at zoom level 20, overzoom real tiles - #4327 (deprecated technique, but it works)
65164           if (data.template.match(/blankTile/) === null) {
65165             data.template = data.template + '?blankTile=false';
65166           }
65167
65168           var esri = rendererBackgroundSource(data);
65169           var cache = {};
65170           var inflight = {};
65171
65172           var _prevCenter; // use a tilemap service to set maximum zoom for esri tiles dynamically
65173           // https://developers.arcgis.com/documentation/tiled-elevation-service/
65174
65175
65176           esri.fetchTilemap = function (center) {
65177             // skip if we have already fetched a tilemap within 5km
65178             if (_prevCenter && geoSphericalDistance(center, _prevCenter) < 5000) return;
65179             _prevCenter = center; // tiles are available globally to zoom level 19, afterward they may or may not be present
65180
65181             var z = 20; // first generate a random url using the template
65182
65183             var dummyUrl = esri.url([1, 2, 3]); // calculate url z/y/x from the lat/long of the center of the map
65184
65185             var x = Math.floor((center[0] + 180) / 360 * Math.pow(2, z));
65186             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
65187
65188             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
65189
65190             d3_json(tilemapUrl).then(function (tilemap) {
65191               if (!tilemap) {
65192                 throw new Error('Unknown Error');
65193               }
65194
65195               var hasTiles = true;
65196
65197               for (var i = 0; i < tilemap.data.length; i++) {
65198                 // 0 means an individual tile in the grid doesn't exist
65199                 if (!tilemap.data[i]) {
65200                   hasTiles = false;
65201                   break;
65202                 }
65203               } // if any tiles are missing at level 20 we restrict maxZoom to 19
65204
65205
65206               esri.zoomExtent[1] = hasTiles ? 22 : 19;
65207             })["catch"](function () {
65208               /* ignore */
65209             });
65210           };
65211
65212           esri.getMetadata = function (center, tileCoord, callback) {
65213             var tileID = tileCoord.slice(0, 3).join('/');
65214             var zoom = Math.min(tileCoord[2], esri.zoomExtent[1]);
65215             var centerPoint = center[0] + ',' + center[1]; // long, lat (as it should be)
65216
65217             var unknown = _t('info_panels.background.unknown');
65218             var metadataLayer;
65219             var vintage = {};
65220             var metadata = {};
65221             if (inflight[tileID]) return;
65222
65223             switch (true) {
65224               case zoom >= 20 && esri.id === 'EsriWorldImageryClarity':
65225                 metadataLayer = 4;
65226                 break;
65227
65228               case zoom >= 19:
65229                 metadataLayer = 3;
65230                 break;
65231
65232               case zoom >= 17:
65233                 metadataLayer = 2;
65234                 break;
65235
65236               case zoom >= 13:
65237                 metadataLayer = 0;
65238                 break;
65239
65240               default:
65241                 metadataLayer = 99;
65242             }
65243
65244             var url; // build up query using the layer appropriate to the current zoom
65245
65246             if (esri.id === 'EsriWorldImagery') {
65247               url = 'https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/';
65248             } else if (esri.id === 'EsriWorldImageryClarity') {
65249               url = 'https://serviceslab.arcgisonline.com/arcgis/rest/services/Clarity_World_Imagery/MapServer/';
65250             }
65251
65252             url += metadataLayer + '/query?returnGeometry=false&geometry=' + centerPoint + '&inSR=4326&geometryType=esriGeometryPoint&outFields=*&f=json';
65253
65254             if (!cache[tileID]) {
65255               cache[tileID] = {};
65256             }
65257
65258             if (cache[tileID] && cache[tileID].metadata) {
65259               return callback(null, cache[tileID].metadata);
65260             } // accurate metadata is only available >= 13
65261
65262
65263             if (metadataLayer === 99) {
65264               vintage = {
65265                 start: null,
65266                 end: null,
65267                 range: null
65268               };
65269               metadata = {
65270                 vintage: null,
65271                 source: unknown,
65272                 description: unknown,
65273                 resolution: unknown,
65274                 accuracy: unknown
65275               };
65276               callback(null, metadata);
65277             } else {
65278               inflight[tileID] = true;
65279               d3_json(url).then(function (result) {
65280                 delete inflight[tileID];
65281
65282                 if (!result) {
65283                   throw new Error('Unknown Error');
65284                 } else if (result.features && result.features.length < 1) {
65285                   throw new Error('No Results');
65286                 } else if (result.error && result.error.message) {
65287                   throw new Error(result.error.message);
65288                 } // pass through the discrete capture date from metadata
65289
65290
65291                 var captureDate = localeDateString(result.features[0].attributes.SRC_DATE2);
65292                 vintage = {
65293                   start: captureDate,
65294                   end: captureDate,
65295                   range: captureDate
65296                 };
65297                 metadata = {
65298                   vintage: vintage,
65299                   source: clean(result.features[0].attributes.NICE_NAME),
65300                   description: clean(result.features[0].attributes.NICE_DESC),
65301                   resolution: clean(+parseFloat(result.features[0].attributes.SRC_RES).toFixed(4)),
65302                   accuracy: clean(+parseFloat(result.features[0].attributes.SRC_ACC).toFixed(4))
65303                 }; // append units - meters
65304
65305                 if (isFinite(metadata.resolution)) {
65306                   metadata.resolution += ' m';
65307                 }
65308
65309                 if (isFinite(metadata.accuracy)) {
65310                   metadata.accuracy += ' m';
65311                 }
65312
65313                 cache[tileID].metadata = metadata;
65314                 if (callback) callback(null, metadata);
65315               })["catch"](function (err) {
65316                 delete inflight[tileID];
65317                 if (callback) callback(err.message);
65318               });
65319             }
65320
65321             function clean(val) {
65322               return String(val).trim() || unknown;
65323             }
65324           };
65325
65326           return esri;
65327         };
65328
65329         rendererBackgroundSource.None = function () {
65330           var source = rendererBackgroundSource({
65331             id: 'none',
65332             template: ''
65333           });
65334
65335           source.name = function () {
65336             return _t('background.none');
65337           };
65338
65339           source.label = function () {
65340             return _t.html('background.none');
65341           };
65342
65343           source.imageryUsed = function () {
65344             return null;
65345           };
65346
65347           source.area = function () {
65348             return -1; // sources in background pane are sorted by area
65349           };
65350
65351           return source;
65352         };
65353
65354         rendererBackgroundSource.Custom = function (template) {
65355           var source = rendererBackgroundSource({
65356             id: 'custom',
65357             template: template
65358           });
65359
65360           source.name = function () {
65361             return _t('background.custom');
65362           };
65363
65364           source.label = function () {
65365             return _t.html('background.custom');
65366           };
65367
65368           source.imageryUsed = function () {
65369             // sanitize personal connection tokens - #6801
65370             var cleaned = source.template(); // from query string parameters
65371
65372             if (cleaned.indexOf('?') !== -1) {
65373               var parts = cleaned.split('?', 2);
65374               var qs = utilStringQs(parts[1]);
65375               ['access_token', 'connectId', 'token'].forEach(function (param) {
65376                 if (qs[param]) {
65377                   qs[param] = '{apikey}';
65378                 }
65379               });
65380               cleaned = parts[0] + '?' + utilQsString(qs, true); // true = soft encode
65381             } // from wms/wmts api path parameters
65382
65383
65384             cleaned = cleaned.replace(/token\/(\w+)/, 'token/{apikey}');
65385             return 'Custom (' + cleaned + ' )';
65386           };
65387
65388           source.area = function () {
65389             return -2; // sources in background pane are sorted by area
65390           };
65391
65392           return source;
65393         };
65394
65395         function rendererTileLayer(context) {
65396           var transformProp = utilPrefixCSSProperty('Transform');
65397           var tiler = utilTiler();
65398           var _tileSize = 256;
65399
65400           var _projection;
65401
65402           var _cache = {};
65403
65404           var _tileOrigin;
65405
65406           var _zoom;
65407
65408           var _source;
65409
65410           function tileSizeAtZoom(d, z) {
65411             var EPSILON = 0.002; // close seams
65412
65413             return _tileSize * Math.pow(2, z - d[2]) / _tileSize + EPSILON;
65414           }
65415
65416           function atZoom(t, distance) {
65417             var power = Math.pow(2, distance);
65418             return [Math.floor(t[0] * power), Math.floor(t[1] * power), t[2] + distance];
65419           }
65420
65421           function lookUp(d) {
65422             for (var up = -1; up > -d[2]; up--) {
65423               var tile = atZoom(d, up);
65424
65425               if (_cache[_source.url(tile)] !== false) {
65426                 return tile;
65427               }
65428             }
65429           }
65430
65431           function uniqueBy(a, n) {
65432             var o = [];
65433             var seen = {};
65434
65435             for (var i = 0; i < a.length; i++) {
65436               if (seen[a[i][n]] === undefined) {
65437                 o.push(a[i]);
65438                 seen[a[i][n]] = true;
65439               }
65440             }
65441
65442             return o;
65443           }
65444
65445           function addSource(d) {
65446             d.push(_source.url(d));
65447             return d;
65448           } // Update tiles based on current state of `projection`.
65449
65450
65451           function background(selection) {
65452             _zoom = geoScaleToZoom(_projection.scale(), _tileSize);
65453             var pixelOffset;
65454
65455             if (_source) {
65456               pixelOffset = [_source.offset()[0] * Math.pow(2, _zoom), _source.offset()[1] * Math.pow(2, _zoom)];
65457             } else {
65458               pixelOffset = [0, 0];
65459             }
65460
65461             var translate = [_projection.translate()[0] + pixelOffset[0], _projection.translate()[1] + pixelOffset[1]];
65462             tiler.scale(_projection.scale() * 2 * Math.PI).translate(translate);
65463             _tileOrigin = [_projection.scale() * Math.PI - translate[0], _projection.scale() * Math.PI - translate[1]];
65464             render(selection);
65465           } // Derive the tiles onscreen, remove those offscreen and position them.
65466           // Important that this part not depend on `_projection` because it's
65467           // rentered when tiles load/error (see #644).
65468
65469
65470           function render(selection) {
65471             if (!_source) return;
65472             var requests = [];
65473             var showDebug = context.getDebug('tile') && !_source.overlay;
65474
65475             if (_source.validZoom(_zoom)) {
65476               tiler.skipNullIsland(!!_source.overlay);
65477               tiler().forEach(function (d) {
65478                 addSource(d);
65479                 if (d[3] === '') return;
65480                 if (typeof d[3] !== 'string') return; // Workaround for #2295
65481
65482                 requests.push(d);
65483
65484                 if (_cache[d[3]] === false && lookUp(d)) {
65485                   requests.push(addSource(lookUp(d)));
65486                 }
65487               });
65488               requests = uniqueBy(requests, 3).filter(function (r) {
65489                 // don't re-request tiles which have failed in the past
65490                 return _cache[r[3]] !== false;
65491               });
65492             }
65493
65494             function load(d3_event, d) {
65495               _cache[d[3]] = true;
65496               select(this).on('error', null).on('load', null).classed('tile-loaded', true);
65497               render(selection);
65498             }
65499
65500             function error(d3_event, d) {
65501               _cache[d[3]] = false;
65502               select(this).on('error', null).on('load', null).remove();
65503               render(selection);
65504             }
65505
65506             function imageTransform(d) {
65507               var ts = _tileSize * Math.pow(2, _zoom - d[2]);
65508
65509               var scale = tileSizeAtZoom(d, _zoom);
65510               return 'translate(' + (d[0] * ts - _tileOrigin[0]) + 'px,' + (d[1] * ts - _tileOrigin[1]) + 'px) ' + 'scale(' + scale + ',' + scale + ')';
65511             }
65512
65513             function tileCenter(d) {
65514               var ts = _tileSize * Math.pow(2, _zoom - d[2]);
65515
65516               return [d[0] * ts - _tileOrigin[0] + ts / 2, d[1] * ts - _tileOrigin[1] + ts / 2];
65517             }
65518
65519             function debugTransform(d) {
65520               var coord = tileCenter(d);
65521               return 'translate(' + coord[0] + 'px,' + coord[1] + 'px)';
65522             } // Pick a representative tile near the center of the viewport
65523             // (This is useful for sampling the imagery vintage)
65524
65525
65526             var dims = tiler.size();
65527             var mapCenter = [dims[0] / 2, dims[1] / 2];
65528             var minDist = Math.max(dims[0], dims[1]);
65529             var nearCenter;
65530             requests.forEach(function (d) {
65531               var c = tileCenter(d);
65532               var dist = geoVecLength(c, mapCenter);
65533
65534               if (dist < minDist) {
65535                 minDist = dist;
65536                 nearCenter = d;
65537               }
65538             });
65539             var image = selection.selectAll('img').data(requests, function (d) {
65540               return d[3];
65541             });
65542             image.exit().style(transformProp, imageTransform).classed('tile-removing', true).classed('tile-center', false).each(function () {
65543               var tile = select(this);
65544               window.setTimeout(function () {
65545                 if (tile.classed('tile-removing')) {
65546                   tile.remove();
65547                 }
65548               }, 300);
65549             });
65550             image.enter().append('img').attr('class', 'tile').attr('draggable', 'false').style('width', _tileSize + 'px').style('height', _tileSize + 'px').attr('src', function (d) {
65551               return d[3];
65552             }).on('error', error).on('load', load).merge(image).style(transformProp, imageTransform).classed('tile-debug', showDebug).classed('tile-removing', false).classed('tile-center', function (d) {
65553               return d === nearCenter;
65554             });
65555             var debug = selection.selectAll('.tile-label-debug').data(showDebug ? requests : [], function (d) {
65556               return d[3];
65557             });
65558             debug.exit().remove();
65559
65560             if (showDebug) {
65561               var debugEnter = debug.enter().append('div').attr('class', 'tile-label-debug');
65562               debugEnter.append('div').attr('class', 'tile-label-debug-coord');
65563               debugEnter.append('div').attr('class', 'tile-label-debug-vintage');
65564               debug = debug.merge(debugEnter);
65565               debug.style(transformProp, debugTransform);
65566               debug.selectAll('.tile-label-debug-coord').html(function (d) {
65567                 return d[2] + ' / ' + d[0] + ' / ' + d[1];
65568               });
65569               debug.selectAll('.tile-label-debug-vintage').each(function (d) {
65570                 var span = select(this);
65571                 var center = context.projection.invert(tileCenter(d));
65572
65573                 _source.getMetadata(center, d, function (err, result) {
65574                   span.html(result && result.vintage && result.vintage.range || _t('info_panels.background.vintage') + ': ' + _t('info_panels.background.unknown'));
65575                 });
65576               });
65577             }
65578           }
65579
65580           background.projection = function (val) {
65581             if (!arguments.length) return _projection;
65582             _projection = val;
65583             return background;
65584           };
65585
65586           background.dimensions = function (val) {
65587             if (!arguments.length) return tiler.size();
65588             tiler.size(val);
65589             return background;
65590           };
65591
65592           background.source = function (val) {
65593             if (!arguments.length) return _source;
65594             _source = val;
65595             _tileSize = _source.tileSize;
65596             _cache = {};
65597             tiler.tileSize(_source.tileSize).zoomExtent(_source.zoomExtent);
65598             return background;
65599           };
65600
65601           return background;
65602         }
65603
65604         var _imageryIndex = null;
65605         function rendererBackground(context) {
65606           var dispatch$1 = dispatch('change');
65607           var detected = utilDetect();
65608           var baseLayer = rendererTileLayer(context).projection(context.projection);
65609           var _isValid = true;
65610           var _overlayLayers = [];
65611           var _brightness = 1;
65612           var _contrast = 1;
65613           var _saturation = 1;
65614           var _sharpness = 1;
65615
65616           function ensureImageryIndex() {
65617             return _mainFileFetcher.get('imagery').then(function (sources) {
65618               if (_imageryIndex) return _imageryIndex;
65619               _imageryIndex = {
65620                 imagery: sources,
65621                 features: {}
65622               }; // use which-polygon to support efficient index and querying for imagery
65623
65624               var features = sources.map(function (source) {
65625                 if (!source.polygon) return null; // workaround for editor-layer-index weirdness..
65626                 // Add an extra array nest to each element in `source.polygon`
65627                 // so the rings are not treated as a bunch of holes:
65628                 // what we have: [ [[outer],[hole],[hole]] ]
65629                 // what we want: [ [[outer]],[[outer]],[[outer]] ]
65630
65631                 var rings = source.polygon.map(function (ring) {
65632                   return [ring];
65633                 });
65634                 var feature = {
65635                   type: 'Feature',
65636                   properties: {
65637                     id: source.id
65638                   },
65639                   geometry: {
65640                     type: 'MultiPolygon',
65641                     coordinates: rings
65642                   }
65643                 };
65644                 _imageryIndex.features[source.id] = feature;
65645                 return feature;
65646               }).filter(Boolean);
65647               _imageryIndex.query = whichPolygon_1({
65648                 type: 'FeatureCollection',
65649                 features: features
65650               }); // Instantiate `rendererBackgroundSource` objects for each source
65651
65652               _imageryIndex.backgrounds = sources.map(function (source) {
65653                 if (source.type === 'bing') {
65654                   return rendererBackgroundSource.Bing(source, dispatch$1);
65655                 } else if (/^EsriWorldImagery/.test(source.id)) {
65656                   return rendererBackgroundSource.Esri(source);
65657                 } else {
65658                   return rendererBackgroundSource(source);
65659                 }
65660               }); // Add 'None'
65661
65662               _imageryIndex.backgrounds.unshift(rendererBackgroundSource.None()); // Add 'Custom'
65663
65664
65665               var template = corePreferences('background-custom-template') || '';
65666               var custom = rendererBackgroundSource.Custom(template);
65667
65668               _imageryIndex.backgrounds.unshift(custom);
65669
65670               return _imageryIndex;
65671             });
65672           }
65673
65674           function background(selection) {
65675             var currSource = baseLayer.source(); // If we are displaying an Esri basemap at high zoom,
65676             // check its tilemap to see how high the zoom can go
65677
65678             if (context.map().zoom() > 18) {
65679               if (currSource && /^EsriWorldImagery/.test(currSource.id)) {
65680                 var center = context.map().center();
65681                 currSource.fetchTilemap(center);
65682               }
65683             } // Is the imagery valid here? - #4827
65684
65685
65686             var sources = background.sources(context.map().extent());
65687             var wasValid = _isValid;
65688             _isValid = !!sources.filter(function (d) {
65689               return d === currSource;
65690             }).length;
65691
65692             if (wasValid !== _isValid) {
65693               // change in valid status
65694               background.updateImagery();
65695             }
65696
65697             var baseFilter = '';
65698
65699             if (detected.cssfilters) {
65700               if (_brightness !== 1) {
65701                 baseFilter += " brightness(".concat(_brightness, ")");
65702               }
65703
65704               if (_contrast !== 1) {
65705                 baseFilter += " contrast(".concat(_contrast, ")");
65706               }
65707
65708               if (_saturation !== 1) {
65709                 baseFilter += " saturate(".concat(_saturation, ")");
65710               }
65711
65712               if (_sharpness < 1) {
65713                 // gaussian blur
65714                 var blur = d3_interpolateNumber(0.5, 5)(1 - _sharpness);
65715                 baseFilter += " blur(".concat(blur, "px)");
65716               }
65717             }
65718
65719             var base = selection.selectAll('.layer-background').data([0]);
65720             base = base.enter().insert('div', '.layer-data').attr('class', 'layer layer-background').merge(base);
65721
65722             if (detected.cssfilters) {
65723               base.style('filter', baseFilter || null);
65724             } else {
65725               base.style('opacity', _brightness);
65726             }
65727
65728             var imagery = base.selectAll('.layer-imagery').data([0]);
65729             imagery.enter().append('div').attr('class', 'layer layer-imagery').merge(imagery).call(baseLayer);
65730             var maskFilter = '';
65731             var mixBlendMode = '';
65732
65733             if (detected.cssfilters && _sharpness > 1) {
65734               // apply unsharp mask
65735               mixBlendMode = 'overlay';
65736               maskFilter = 'saturate(0) blur(3px) invert(1)';
65737               var contrast = _sharpness - 1;
65738               maskFilter += " contrast(".concat(contrast, ")");
65739               var brightness = d3_interpolateNumber(1, 0.85)(_sharpness - 1);
65740               maskFilter += " brightness(".concat(brightness, ")");
65741             }
65742
65743             var mask = base.selectAll('.layer-unsharp-mask').data(detected.cssfilters && _sharpness > 1 ? [0] : []);
65744             mask.exit().remove();
65745             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);
65746             var overlays = selection.selectAll('.layer-overlay').data(_overlayLayers, function (d) {
65747               return d.source().name();
65748             });
65749             overlays.exit().remove();
65750             overlays.enter().insert('div', '.layer-data').attr('class', 'layer layer-overlay').merge(overlays).each(function (layer, i, nodes) {
65751               return select(nodes[i]).call(layer);
65752             });
65753           }
65754
65755           background.updateImagery = function () {
65756             var currSource = baseLayer.source();
65757             if (context.inIntro() || !currSource) return;
65758
65759             var o = _overlayLayers.filter(function (d) {
65760               return !d.source().isLocatorOverlay() && !d.source().isHidden();
65761             }).map(function (d) {
65762               return d.source().id;
65763             }).join(',');
65764
65765             var meters = geoOffsetToMeters(currSource.offset());
65766             var EPSILON = 0.01;
65767             var x = +meters[0].toFixed(2);
65768             var y = +meters[1].toFixed(2);
65769             var hash = utilStringQs(window.location.hash);
65770             var id = currSource.id;
65771
65772             if (id === 'custom') {
65773               id = "custom:".concat(currSource.template());
65774             }
65775
65776             if (id) {
65777               hash.background = id;
65778             } else {
65779               delete hash.background;
65780             }
65781
65782             if (o) {
65783               hash.overlays = o;
65784             } else {
65785               delete hash.overlays;
65786             }
65787
65788             if (Math.abs(x) > EPSILON || Math.abs(y) > EPSILON) {
65789               hash.offset = "".concat(x, ",").concat(y);
65790             } else {
65791               delete hash.offset;
65792             }
65793
65794             if (!window.mocha) {
65795               window.location.replace('#' + utilQsString(hash, true));
65796             }
65797
65798             var imageryUsed = [];
65799             var photoOverlaysUsed = [];
65800             var currUsed = currSource.imageryUsed();
65801
65802             if (currUsed && _isValid) {
65803               imageryUsed.push(currUsed);
65804             }
65805
65806             _overlayLayers.filter(function (d) {
65807               return !d.source().isLocatorOverlay() && !d.source().isHidden();
65808             }).forEach(function (d) {
65809               return imageryUsed.push(d.source().imageryUsed());
65810             });
65811
65812             var dataLayer = context.layers().layer('data');
65813
65814             if (dataLayer && dataLayer.enabled() && dataLayer.hasData()) {
65815               imageryUsed.push(dataLayer.getSrc());
65816             }
65817
65818             var photoOverlayLayers = {
65819               streetside: 'Bing Streetside',
65820               mapillary: 'Mapillary Images',
65821               'mapillary-map-features': 'Mapillary Map Features',
65822               'mapillary-signs': 'Mapillary Signs',
65823               openstreetcam: 'OpenStreetCam Images'
65824             };
65825
65826             for (var layerID in photoOverlayLayers) {
65827               var layer = context.layers().layer(layerID);
65828
65829               if (layer && layer.enabled()) {
65830                 photoOverlaysUsed.push(layerID);
65831                 imageryUsed.push(photoOverlayLayers[layerID]);
65832               }
65833             }
65834
65835             context.history().imageryUsed(imageryUsed);
65836             context.history().photoOverlaysUsed(photoOverlaysUsed);
65837           };
65838
65839           var _checkedBlocklists;
65840
65841           background.sources = function (extent, zoom, includeCurrent) {
65842             if (!_imageryIndex) return []; // called before init()?
65843
65844             var visible = {};
65845             (_imageryIndex.query.bbox(extent.rectangle(), true) || []).forEach(function (d) {
65846               return visible[d.id] = true;
65847             });
65848             var currSource = baseLayer.source();
65849             var osm = context.connection();
65850             var blocklists = osm && osm.imageryBlocklists();
65851
65852             if (blocklists && blocklists !== _checkedBlocklists) {
65853               _imageryIndex.backgrounds.forEach(function (source) {
65854                 source.isBlocked = blocklists.some(function (blocklist) {
65855                   return blocklist.test(source.template());
65856                 });
65857               });
65858
65859               _checkedBlocklists = blocklists;
65860             }
65861
65862             return _imageryIndex.backgrounds.filter(function (source) {
65863               if (includeCurrent && currSource === source) return true; // optionally always include the current imagery
65864
65865               if (source.isBlocked) return false; // even bundled sources may be blocked - #7905
65866
65867               if (!source.polygon) return true; // always include imagery with worldwide coverage
65868
65869               if (zoom && zoom < 6) return false; // optionally exclude local imagery at low zooms
65870
65871               return visible[source.id]; // include imagery visible in given extent
65872             });
65873           };
65874
65875           background.dimensions = function (val) {
65876             if (!val) return;
65877             baseLayer.dimensions(val);
65878
65879             _overlayLayers.forEach(function (layer) {
65880               return layer.dimensions(val);
65881             });
65882           };
65883
65884           background.baseLayerSource = function (d) {
65885             if (!arguments.length) return baseLayer.source(); // test source against OSM imagery blocklists..
65886
65887             var osm = context.connection();
65888             if (!osm) return background;
65889             var blocklists = osm.imageryBlocklists();
65890             var template = d.template();
65891             var fail = false;
65892             var tested = 0;
65893             var regex;
65894
65895             for (var i = 0; i < blocklists.length; i++) {
65896               regex = blocklists[i];
65897               fail = regex.test(template);
65898               tested++;
65899               if (fail) break;
65900             } // ensure at least one test was run.
65901
65902
65903             if (!tested) {
65904               regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
65905               fail = regex.test(template);
65906             }
65907
65908             baseLayer.source(!fail ? d : background.findSource('none'));
65909             dispatch$1.call('change');
65910             background.updateImagery();
65911             return background;
65912           };
65913
65914           background.findSource = function (id) {
65915             if (!id || !_imageryIndex) return null; // called before init()?
65916
65917             return _imageryIndex.backgrounds.find(function (d) {
65918               return d.id && d.id === id;
65919             });
65920           };
65921
65922           background.bing = function () {
65923             background.baseLayerSource(background.findSource('Bing'));
65924           };
65925
65926           background.showsLayer = function (d) {
65927             var currSource = baseLayer.source();
65928             if (!d || !currSource) return false;
65929             return d.id === currSource.id || _overlayLayers.some(function (layer) {
65930               return d.id === layer.source().id;
65931             });
65932           };
65933
65934           background.overlayLayerSources = function () {
65935             return _overlayLayers.map(function (layer) {
65936               return layer.source();
65937             });
65938           };
65939
65940           background.toggleOverlayLayer = function (d) {
65941             var layer;
65942
65943             for (var i = 0; i < _overlayLayers.length; i++) {
65944               layer = _overlayLayers[i];
65945
65946               if (layer.source() === d) {
65947                 _overlayLayers.splice(i, 1);
65948
65949                 dispatch$1.call('change');
65950                 background.updateImagery();
65951                 return;
65952               }
65953             }
65954
65955             layer = rendererTileLayer(context).source(d).projection(context.projection).dimensions(baseLayer.dimensions());
65956
65957             _overlayLayers.push(layer);
65958
65959             dispatch$1.call('change');
65960             background.updateImagery();
65961           };
65962
65963           background.nudge = function (d, zoom) {
65964             var currSource = baseLayer.source();
65965
65966             if (currSource) {
65967               currSource.nudge(d, zoom);
65968               dispatch$1.call('change');
65969               background.updateImagery();
65970             }
65971
65972             return background;
65973           };
65974
65975           background.offset = function (d) {
65976             var currSource = baseLayer.source();
65977
65978             if (!arguments.length) {
65979               return currSource && currSource.offset() || [0, 0];
65980             }
65981
65982             if (currSource) {
65983               currSource.offset(d);
65984               dispatch$1.call('change');
65985               background.updateImagery();
65986             }
65987
65988             return background;
65989           };
65990
65991           background.brightness = function (d) {
65992             if (!arguments.length) return _brightness;
65993             _brightness = d;
65994             if (context.mode()) dispatch$1.call('change');
65995             return background;
65996           };
65997
65998           background.contrast = function (d) {
65999             if (!arguments.length) return _contrast;
66000             _contrast = d;
66001             if (context.mode()) dispatch$1.call('change');
66002             return background;
66003           };
66004
66005           background.saturation = function (d) {
66006             if (!arguments.length) return _saturation;
66007             _saturation = d;
66008             if (context.mode()) dispatch$1.call('change');
66009             return background;
66010           };
66011
66012           background.sharpness = function (d) {
66013             if (!arguments.length) return _sharpness;
66014             _sharpness = d;
66015             if (context.mode()) dispatch$1.call('change');
66016             return background;
66017           };
66018
66019           var _loadPromise;
66020
66021           background.ensureLoaded = function () {
66022             if (_loadPromise) return _loadPromise;
66023
66024             function parseMapParams(qmap) {
66025               if (!qmap) return false;
66026               var params = qmap.split('/').map(Number);
66027               if (params.length < 3 || params.some(isNaN)) return false;
66028               return geoExtent([params[2], params[1]]); // lon,lat
66029             }
66030
66031             var hash = utilStringQs(window.location.hash);
66032             var requested = hash.background || hash.layer;
66033             var extent = parseMapParams(hash.map);
66034             return _loadPromise = ensureImageryIndex().then(function (imageryIndex) {
66035               var first = imageryIndex.backgrounds.length && imageryIndex.backgrounds[0];
66036               var best;
66037
66038               if (!requested && extent) {
66039                 best = background.sources(extent).find(function (s) {
66040                   return s.best();
66041                 });
66042               } // Decide which background layer to display
66043
66044
66045               if (requested && requested.indexOf('custom:') === 0) {
66046                 var template = requested.replace(/^custom:/, '');
66047                 var custom = background.findSource('custom');
66048                 background.baseLayerSource(custom.template(template));
66049                 corePreferences('background-custom-template', template);
66050               } else {
66051                 background.baseLayerSource(background.findSource(requested) || best || background.findSource(corePreferences('background-last-used')) || background.findSource('Bing') || first || background.findSource('none'));
66052               }
66053
66054               var locator = imageryIndex.backgrounds.find(function (d) {
66055                 return d.overlay && d["default"];
66056               });
66057
66058               if (locator) {
66059                 background.toggleOverlayLayer(locator);
66060               }
66061
66062               var overlays = (hash.overlays || '').split(',');
66063               overlays.forEach(function (overlay) {
66064                 overlay = background.findSource(overlay);
66065
66066                 if (overlay) {
66067                   background.toggleOverlayLayer(overlay);
66068                 }
66069               });
66070
66071               if (hash.gpx) {
66072                 var gpx = context.layers().layer('data');
66073
66074                 if (gpx) {
66075                   gpx.url(hash.gpx, '.gpx');
66076                 }
66077               }
66078
66079               if (hash.offset) {
66080                 var offset = hash.offset.replace(/;/g, ',').split(',').map(function (n) {
66081                   return !isNaN(n) && n;
66082                 });
66083
66084                 if (offset.length === 2) {
66085                   background.offset(geoMetersToOffset(offset));
66086                 }
66087               }
66088             })["catch"](function () {
66089               /* ignore */
66090             });
66091           };
66092
66093           return utilRebind(background, dispatch$1, 'on');
66094         }
66095
66096         function rendererFeatures(context) {
66097           var dispatch$1 = dispatch('change', 'redraw');
66098           var features = utilRebind({}, dispatch$1, 'on');
66099
66100           var _deferred = new Set();
66101
66102           var traffic_roads = {
66103             'motorway': true,
66104             'motorway_link': true,
66105             'trunk': true,
66106             'trunk_link': true,
66107             'primary': true,
66108             'primary_link': true,
66109             'secondary': true,
66110             'secondary_link': true,
66111             'tertiary': true,
66112             'tertiary_link': true,
66113             'residential': true,
66114             'unclassified': true,
66115             'living_street': true
66116           };
66117           var service_roads = {
66118             'service': true,
66119             'road': true,
66120             'track': true
66121           };
66122           var paths = {
66123             'path': true,
66124             'footway': true,
66125             'cycleway': true,
66126             'bridleway': true,
66127             'steps': true,
66128             'pedestrian': true
66129           };
66130           var past_futures = {
66131             'proposed': true,
66132             'construction': true,
66133             'abandoned': true,
66134             'dismantled': true,
66135             'disused': true,
66136             'razed': true,
66137             'demolished': true,
66138             'obliterated': true
66139           };
66140           var _cullFactor = 1;
66141           var _cache = {};
66142           var _rules = {};
66143           var _stats = {};
66144           var _keys = [];
66145           var _hidden = [];
66146           var _forceVisible = {};
66147
66148           function update() {
66149             if (!window.mocha) {
66150               var hash = utilStringQs(window.location.hash);
66151               var disabled = features.disabled();
66152
66153               if (disabled.length) {
66154                 hash.disable_features = disabled.join(',');
66155               } else {
66156                 delete hash.disable_features;
66157               }
66158
66159               window.location.replace('#' + utilQsString(hash, true));
66160               corePreferences('disabled-features', disabled.join(','));
66161             }
66162
66163             _hidden = features.hidden();
66164             dispatch$1.call('change');
66165             dispatch$1.call('redraw');
66166           }
66167
66168           function defineRule(k, filter, max) {
66169             var isEnabled = true;
66170
66171             _keys.push(k);
66172
66173             _rules[k] = {
66174               filter: filter,
66175               enabled: isEnabled,
66176               // whether the user wants it enabled..
66177               count: 0,
66178               currentMax: max || Infinity,
66179               defaultMax: max || Infinity,
66180               enable: function enable() {
66181                 this.enabled = true;
66182                 this.currentMax = this.defaultMax;
66183               },
66184               disable: function disable() {
66185                 this.enabled = false;
66186                 this.currentMax = 0;
66187               },
66188               hidden: function hidden() {
66189                 return this.count === 0 && !this.enabled || this.count > this.currentMax * _cullFactor;
66190               },
66191               autoHidden: function autoHidden() {
66192                 return this.hidden() && this.currentMax > 0;
66193               }
66194             };
66195           }
66196
66197           defineRule('points', function isPoint(tags, geometry) {
66198             return geometry === 'point';
66199           }, 200);
66200           defineRule('traffic_roads', function isTrafficRoad(tags) {
66201             return traffic_roads[tags.highway];
66202           });
66203           defineRule('service_roads', function isServiceRoad(tags) {
66204             return service_roads[tags.highway];
66205           });
66206           defineRule('paths', function isPath(tags) {
66207             return paths[tags.highway];
66208           });
66209           defineRule('buildings', function isBuilding(tags) {
66210             return !!tags.building && tags.building !== 'no' || tags.parking === 'multi-storey' || tags.parking === 'sheds' || tags.parking === 'carports' || tags.parking === 'garage_boxes';
66211           }, 250);
66212           defineRule('building_parts', function isBuildingPart(tags) {
66213             return tags['building:part'];
66214           });
66215           defineRule('indoor', function isIndoor(tags) {
66216             return tags.indoor;
66217           });
66218           defineRule('landuse', function isLanduse(tags, geometry) {
66219             return geometry === 'area' && !_rules.buildings.filter(tags) && !_rules.building_parts.filter(tags) && !_rules.indoor.filter(tags) && !_rules.water.filter(tags) && !_rules.pistes.filter(tags);
66220           });
66221           defineRule('boundaries', function isBoundary(tags) {
66222             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);
66223           });
66224           defineRule('water', function isWater(tags) {
66225             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';
66226           });
66227           defineRule('rail', function isRail(tags) {
66228             return (!!tags.railway || tags.landuse === 'railway') && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]);
66229           });
66230           defineRule('pistes', function isPiste(tags) {
66231             return tags['piste:type'];
66232           });
66233           defineRule('aerialways', function isPiste(tags) {
66234             return tags.aerialway && tags.aerialway !== 'yes' && tags.aerialway !== 'station';
66235           });
66236           defineRule('power', function isPower(tags) {
66237             return !!tags.power;
66238           }); // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
66239
66240           defineRule('past_future', function isPastFuture(tags) {
66241             if (traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]) {
66242               return false;
66243             }
66244
66245             var strings = Object.keys(tags);
66246
66247             for (var i = 0; i < strings.length; i++) {
66248               var s = strings[i];
66249
66250               if (past_futures[s] || past_futures[tags[s]]) {
66251                 return true;
66252               }
66253             }
66254
66255             return false;
66256           }); // Lines or areas that don't match another feature filter.
66257           // IMPORTANT: The 'others' feature must be the last one defined,
66258           //   so that code in getMatches can skip this test if `hasMatch = true`
66259
66260           defineRule('others', function isOther(tags, geometry) {
66261             return geometry === 'line' || geometry === 'area';
66262           });
66263
66264           features.features = function () {
66265             return _rules;
66266           };
66267
66268           features.keys = function () {
66269             return _keys;
66270           };
66271
66272           features.enabled = function (k) {
66273             if (!arguments.length) {
66274               return _keys.filter(function (k) {
66275                 return _rules[k].enabled;
66276               });
66277             }
66278
66279             return _rules[k] && _rules[k].enabled;
66280           };
66281
66282           features.disabled = function (k) {
66283             if (!arguments.length) {
66284               return _keys.filter(function (k) {
66285                 return !_rules[k].enabled;
66286               });
66287             }
66288
66289             return _rules[k] && !_rules[k].enabled;
66290           };
66291
66292           features.hidden = function (k) {
66293             if (!arguments.length) {
66294               return _keys.filter(function (k) {
66295                 return _rules[k].hidden();
66296               });
66297             }
66298
66299             return _rules[k] && _rules[k].hidden();
66300           };
66301
66302           features.autoHidden = function (k) {
66303             if (!arguments.length) {
66304               return _keys.filter(function (k) {
66305                 return _rules[k].autoHidden();
66306               });
66307             }
66308
66309             return _rules[k] && _rules[k].autoHidden();
66310           };
66311
66312           features.enable = function (k) {
66313             if (_rules[k] && !_rules[k].enabled) {
66314               _rules[k].enable();
66315
66316               update();
66317             }
66318           };
66319
66320           features.enableAll = function () {
66321             var didEnable = false;
66322
66323             for (var k in _rules) {
66324               if (!_rules[k].enabled) {
66325                 didEnable = true;
66326
66327                 _rules[k].enable();
66328               }
66329             }
66330
66331             if (didEnable) update();
66332           };
66333
66334           features.disable = function (k) {
66335             if (_rules[k] && _rules[k].enabled) {
66336               _rules[k].disable();
66337
66338               update();
66339             }
66340           };
66341
66342           features.disableAll = function () {
66343             var didDisable = false;
66344
66345             for (var k in _rules) {
66346               if (_rules[k].enabled) {
66347                 didDisable = true;
66348
66349                 _rules[k].disable();
66350               }
66351             }
66352
66353             if (didDisable) update();
66354           };
66355
66356           features.toggle = function (k) {
66357             if (_rules[k]) {
66358               (function (f) {
66359                 return f.enabled ? f.disable() : f.enable();
66360               })(_rules[k]);
66361
66362               update();
66363             }
66364           };
66365
66366           features.resetStats = function () {
66367             for (var i = 0; i < _keys.length; i++) {
66368               _rules[_keys[i]].count = 0;
66369             }
66370
66371             dispatch$1.call('change');
66372           };
66373
66374           features.gatherStats = function (d, resolver, dimensions) {
66375             var needsRedraw = false;
66376             var types = utilArrayGroupBy(d, 'type');
66377             var entities = [].concat(types.relation || [], types.way || [], types.node || []);
66378             var currHidden, geometry, matches, i, j;
66379
66380             for (i = 0; i < _keys.length; i++) {
66381               _rules[_keys[i]].count = 0;
66382             } // adjust the threshold for point/building culling based on viewport size..
66383             // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
66384
66385
66386             _cullFactor = dimensions[0] * dimensions[1] / 1000000;
66387
66388             for (i = 0; i < entities.length; i++) {
66389               geometry = entities[i].geometry(resolver);
66390               matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
66391
66392               for (j = 0; j < matches.length; j++) {
66393                 _rules[matches[j]].count++;
66394               }
66395             }
66396
66397             currHidden = features.hidden();
66398
66399             if (currHidden !== _hidden) {
66400               _hidden = currHidden;
66401               needsRedraw = true;
66402               dispatch$1.call('change');
66403             }
66404
66405             return needsRedraw;
66406           };
66407
66408           features.stats = function () {
66409             for (var i = 0; i < _keys.length; i++) {
66410               _stats[_keys[i]] = _rules[_keys[i]].count;
66411             }
66412
66413             return _stats;
66414           };
66415
66416           features.clear = function (d) {
66417             for (var i = 0; i < d.length; i++) {
66418               features.clearEntity(d[i]);
66419             }
66420           };
66421
66422           features.clearEntity = function (entity) {
66423             delete _cache[osmEntity.key(entity)];
66424           };
66425
66426           features.reset = function () {
66427             Array.from(_deferred).forEach(function (handle) {
66428               window.cancelIdleCallback(handle);
66429
66430               _deferred["delete"](handle);
66431             });
66432             _cache = {};
66433           }; // only certain relations are worth checking
66434
66435
66436           function relationShouldBeChecked(relation) {
66437             // multipolygon features have `area` geometry and aren't checked here
66438             return relation.tags.type === 'boundary';
66439           }
66440
66441           features.getMatches = function (entity, resolver, geometry) {
66442             if (geometry === 'vertex' || geometry === 'relation' && !relationShouldBeChecked(entity)) return {};
66443             var ent = osmEntity.key(entity);
66444
66445             if (!_cache[ent]) {
66446               _cache[ent] = {};
66447             }
66448
66449             if (!_cache[ent].matches) {
66450               var matches = {};
66451               var hasMatch = false;
66452
66453               for (var i = 0; i < _keys.length; i++) {
66454                 if (_keys[i] === 'others') {
66455                   if (hasMatch) continue; // If an entity...
66456                   //   1. is a way that hasn't matched other 'interesting' feature rules,
66457
66458                   if (entity.type === 'way') {
66459                     var parents = features.getParents(entity, resolver, geometry); //   2a. belongs only to a single multipolygon relation
66460
66461                     if (parents.length === 1 && parents[0].isMultipolygon() || // 2b. or belongs only to boundary relations
66462                     parents.length > 0 && parents.every(function (parent) {
66463                       return parent.tags.type === 'boundary';
66464                     })) {
66465                       // ...then match whatever feature rules the parent relation has matched.
66466                       // see #2548, #2887
66467                       //
66468                       // IMPORTANT:
66469                       // For this to work, getMatches must be called on relations before ways.
66470                       //
66471                       var pkey = osmEntity.key(parents[0]);
66472
66473                       if (_cache[pkey] && _cache[pkey].matches) {
66474                         matches = Object.assign({}, _cache[pkey].matches); // shallow copy
66475
66476                         continue;
66477                       }
66478                     }
66479                   }
66480                 }
66481
66482                 if (_rules[_keys[i]].filter(entity.tags, geometry)) {
66483                   matches[_keys[i]] = hasMatch = true;
66484                 }
66485               }
66486
66487               _cache[ent].matches = matches;
66488             }
66489
66490             return _cache[ent].matches;
66491           };
66492
66493           features.getParents = function (entity, resolver, geometry) {
66494             if (geometry === 'point') return [];
66495             var ent = osmEntity.key(entity);
66496
66497             if (!_cache[ent]) {
66498               _cache[ent] = {};
66499             }
66500
66501             if (!_cache[ent].parents) {
66502               var parents = [];
66503
66504               if (geometry === 'vertex') {
66505                 parents = resolver.parentWays(entity);
66506               } else {
66507                 // 'line', 'area', 'relation'
66508                 parents = resolver.parentRelations(entity);
66509               }
66510
66511               _cache[ent].parents = parents;
66512             }
66513
66514             return _cache[ent].parents;
66515           };
66516
66517           features.isHiddenPreset = function (preset, geometry) {
66518             if (!_hidden.length) return false;
66519             if (!preset.tags) return false;
66520             var test = preset.setTags({}, geometry);
66521
66522             for (var key in _rules) {
66523               if (_rules[key].filter(test, geometry)) {
66524                 if (_hidden.indexOf(key) !== -1) {
66525                   return key;
66526                 }
66527
66528                 return false;
66529               }
66530             }
66531
66532             return false;
66533           };
66534
66535           features.isHiddenFeature = function (entity, resolver, geometry) {
66536             if (!_hidden.length) return false;
66537             if (!entity.version) return false;
66538             if (_forceVisible[entity.id]) return false;
66539             var matches = Object.keys(features.getMatches(entity, resolver, geometry));
66540             return matches.length && matches.every(function (k) {
66541               return features.hidden(k);
66542             });
66543           };
66544
66545           features.isHiddenChild = function (entity, resolver, geometry) {
66546             if (!_hidden.length) return false;
66547             if (!entity.version || geometry === 'point') return false;
66548             if (_forceVisible[entity.id]) return false;
66549             var parents = features.getParents(entity, resolver, geometry);
66550             if (!parents.length) return false;
66551
66552             for (var i = 0; i < parents.length; i++) {
66553               if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
66554                 return false;
66555               }
66556             }
66557
66558             return true;
66559           };
66560
66561           features.hasHiddenConnections = function (entity, resolver) {
66562             if (!_hidden.length) return false;
66563             var childNodes, connections;
66564
66565             if (entity.type === 'midpoint') {
66566               childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
66567               connections = [];
66568             } else {
66569               childNodes = entity.nodes ? resolver.childNodes(entity) : [];
66570               connections = features.getParents(entity, resolver, entity.geometry(resolver));
66571             } // gather ways connected to child nodes..
66572
66573
66574             connections = childNodes.reduce(function (result, e) {
66575               return resolver.isShared(e) ? utilArrayUnion(result, resolver.parentWays(e)) : result;
66576             }, connections);
66577             return connections.some(function (e) {
66578               return features.isHidden(e, resolver, e.geometry(resolver));
66579             });
66580           };
66581
66582           features.isHidden = function (entity, resolver, geometry) {
66583             if (!_hidden.length) return false;
66584             if (!entity.version) return false;
66585             var fn = geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature;
66586             return fn(entity, resolver, geometry);
66587           };
66588
66589           features.filter = function (d, resolver) {
66590             if (!_hidden.length) return d;
66591             var result = [];
66592
66593             for (var i = 0; i < d.length; i++) {
66594               var entity = d[i];
66595
66596               if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
66597                 result.push(entity);
66598               }
66599             }
66600
66601             return result;
66602           };
66603
66604           features.forceVisible = function (entityIDs) {
66605             if (!arguments.length) return Object.keys(_forceVisible);
66606             _forceVisible = {};
66607
66608             for (var i = 0; i < entityIDs.length; i++) {
66609               _forceVisible[entityIDs[i]] = true;
66610               var entity = context.hasEntity(entityIDs[i]);
66611
66612               if (entity && entity.type === 'relation') {
66613                 // also show relation members (one level deep)
66614                 for (var j in entity.members) {
66615                   _forceVisible[entity.members[j].id] = true;
66616                 }
66617               }
66618             }
66619
66620             return features;
66621           };
66622
66623           features.init = function () {
66624             var storage = corePreferences('disabled-features');
66625
66626             if (storage) {
66627               var storageDisabled = storage.replace(/;/g, ',').split(',');
66628               storageDisabled.forEach(features.disable);
66629             }
66630
66631             var hash = utilStringQs(window.location.hash);
66632
66633             if (hash.disable_features) {
66634               var hashDisabled = hash.disable_features.replace(/;/g, ',').split(',');
66635               hashDisabled.forEach(features.disable);
66636             }
66637           }; // warm up the feature matching cache upon merging fetched data
66638
66639
66640           context.history().on('merge.features', function (newEntities) {
66641             if (!newEntities) return;
66642             var handle = window.requestIdleCallback(function () {
66643               var graph = context.graph();
66644               var types = utilArrayGroupBy(newEntities, 'type'); // ensure that getMatches is called on relations before ways
66645
66646               var entities = [].concat(types.relation || [], types.way || [], types.node || []);
66647
66648               for (var i = 0; i < entities.length; i++) {
66649                 var geometry = entities[i].geometry(graph);
66650                 features.getMatches(entities[i], graph, geometry);
66651               }
66652             });
66653
66654             _deferred.add(handle);
66655           });
66656           return features;
66657         }
66658
66659         //
66660         // - the activeID - nope
66661         // - 1 away (adjacent) to the activeID - yes (vertices will be merged)
66662         // - 2 away from the activeID - nope (would create a self intersecting segment)
66663         // - all others on a linear way - yes
66664         // - all others on a closed way - nope (would create a self intersecting polygon)
66665         //
66666         // returns
66667         // 0 = active vertex - no touch/connect
66668         // 1 = passive vertex - yes touch/connect
66669         // 2 = adjacent vertex - yes but pay attention segmenting a line here
66670         //
66671
66672         function svgPassiveVertex(node, graph, activeID) {
66673           if (!activeID) return 1;
66674           if (activeID === node.id) return 0;
66675           var parents = graph.parentWays(node);
66676           var i, j, nodes, isClosed, ix1, ix2, ix3, ix4, max;
66677
66678           for (i = 0; i < parents.length; i++) {
66679             nodes = parents[i].nodes;
66680             isClosed = parents[i].isClosed();
66681
66682             for (j = 0; j < nodes.length; j++) {
66683               // find this vertex, look nearby
66684               if (nodes[j] === node.id) {
66685                 ix1 = j - 2;
66686                 ix2 = j - 1;
66687                 ix3 = j + 1;
66688                 ix4 = j + 2;
66689
66690                 if (isClosed) {
66691                   // wraparound if needed
66692                   max = nodes.length - 1;
66693                   if (ix1 < 0) ix1 = max + ix1;
66694                   if (ix2 < 0) ix2 = max + ix2;
66695                   if (ix3 > max) ix3 = ix3 - max;
66696                   if (ix4 > max) ix4 = ix4 - max;
66697                 }
66698
66699                 if (nodes[ix1] === activeID) return 0; // no - prevent self intersect
66700                 else if (nodes[ix2] === activeID) return 2; // ok - adjacent
66701                   else if (nodes[ix3] === activeID) return 2; // ok - adjacent
66702                     else if (nodes[ix4] === activeID) return 0; // no - prevent self intersect
66703                       else if (isClosed && nodes.indexOf(activeID) !== -1) return 0; // no - prevent self intersect
66704               }
66705             }
66706           }
66707
66708           return 1; // ok
66709         }
66710         function svgMarkerSegments(projection, graph, dt, shouldReverse, bothDirections) {
66711           return function (entity) {
66712             var i = 0;
66713             var offset = dt;
66714             var segments = [];
66715             var clip = d3_geoIdentity().clipExtent(projection.clipExtent()).stream;
66716             var coordinates = graph.childNodes(entity).map(function (n) {
66717               return n.loc;
66718             });
66719             var a, b;
66720
66721             if (shouldReverse(entity)) {
66722               coordinates.reverse();
66723             }
66724
66725             d3_geoStream({
66726               type: 'LineString',
66727               coordinates: coordinates
66728             }, projection.stream(clip({
66729               lineStart: function lineStart() {},
66730               lineEnd: function lineEnd() {
66731                 a = null;
66732               },
66733               point: function point(x, y) {
66734                 b = [x, y];
66735
66736                 if (a) {
66737                   var span = geoVecLength(a, b) - offset;
66738
66739                   if (span >= 0) {
66740                     var heading = geoVecAngle(a, b);
66741                     var dx = dt * Math.cos(heading);
66742                     var dy = dt * Math.sin(heading);
66743                     var p = [a[0] + offset * Math.cos(heading), a[1] + offset * Math.sin(heading)]; // gather coordinates
66744
66745                     var coord = [a, p];
66746
66747                     for (span -= dt; span >= 0; span -= dt) {
66748                       p = geoVecAdd(p, [dx, dy]);
66749                       coord.push(p);
66750                     }
66751
66752                     coord.push(b); // generate svg paths
66753
66754                     var segment = '';
66755                     var j;
66756
66757                     for (j = 0; j < coord.length; j++) {
66758                       segment += (j === 0 ? 'M' : 'L') + coord[j][0] + ',' + coord[j][1];
66759                     }
66760
66761                     segments.push({
66762                       id: entity.id,
66763                       index: i++,
66764                       d: segment
66765                     });
66766
66767                     if (bothDirections(entity)) {
66768                       segment = '';
66769
66770                       for (j = coord.length - 1; j >= 0; j--) {
66771                         segment += (j === coord.length - 1 ? 'M' : 'L') + coord[j][0] + ',' + coord[j][1];
66772                       }
66773
66774                       segments.push({
66775                         id: entity.id,
66776                         index: i++,
66777                         d: segment
66778                       });
66779                     }
66780                   }
66781
66782                   offset = -span;
66783                 }
66784
66785                 a = b;
66786               }
66787             })));
66788             return segments;
66789           };
66790         }
66791         function svgPath(projection, graph, isArea) {
66792           // Explanation of magic numbers:
66793           // "padding" here allows space for strokes to extend beyond the viewport,
66794           // so that the stroke isn't drawn along the edge of the viewport when
66795           // the shape is clipped.
66796           //
66797           // When drawing lines, pad viewport by 5px.
66798           // When drawing areas, pad viewport by 65px in each direction to allow
66799           // for 60px area fill stroke (see ".fill-partial path.fill" css rule)
66800           var cache = {};
66801           var padding = isArea ? 65 : 5;
66802           var viewport = projection.clipExtent();
66803           var paddedExtent = [[viewport[0][0] - padding, viewport[0][1] - padding], [viewport[1][0] + padding, viewport[1][1] + padding]];
66804           var clip = d3_geoIdentity().clipExtent(paddedExtent).stream;
66805           var project = projection.stream;
66806           var path = d3_geoPath().projection({
66807             stream: function stream(output) {
66808               return project(clip(output));
66809             }
66810           });
66811
66812           var svgpath = function svgpath(entity) {
66813             if (entity.id in cache) {
66814               return cache[entity.id];
66815             } else {
66816               return cache[entity.id] = path(entity.asGeoJSON(graph));
66817             }
66818           };
66819
66820           svgpath.geojson = function (d) {
66821             if (d.__featurehash__ !== undefined) {
66822               if (d.__featurehash__ in cache) {
66823                 return cache[d.__featurehash__];
66824               } else {
66825                 return cache[d.__featurehash__] = path(d);
66826               }
66827             } else {
66828               return path(d);
66829             }
66830           };
66831
66832           return svgpath;
66833         }
66834         function svgPointTransform(projection) {
66835           var svgpoint = function svgpoint(entity) {
66836             // http://jsperf.com/short-array-join
66837             var pt = projection(entity.loc);
66838             return 'translate(' + pt[0] + ',' + pt[1] + ')';
66839           };
66840
66841           svgpoint.geojson = function (d) {
66842             return svgpoint(d.properties.entity);
66843           };
66844
66845           return svgpoint;
66846         }
66847         function svgRelationMemberTags(graph) {
66848           return function (entity) {
66849             var tags = entity.tags;
66850             var shouldCopyMultipolygonTags = !entity.hasInterestingTags();
66851             graph.parentRelations(entity).forEach(function (relation) {
66852               var type = relation.tags.type;
66853
66854               if (type === 'multipolygon' && shouldCopyMultipolygonTags || type === 'boundary') {
66855                 tags = Object.assign({}, relation.tags, tags);
66856               }
66857             });
66858             return tags;
66859           };
66860         }
66861         function svgSegmentWay(way, graph, activeID) {
66862           // When there is no activeID, we can memoize this expensive computation
66863           if (activeID === undefined) {
66864             return graph["transient"](way, 'waySegments', getWaySegments);
66865           } else {
66866             return getWaySegments();
66867           }
66868
66869           function getWaySegments() {
66870             var isActiveWay = way.nodes.indexOf(activeID) !== -1;
66871             var features = {
66872               passive: [],
66873               active: []
66874             };
66875             var start = {};
66876             var end = {};
66877             var node, type;
66878
66879             for (var i = 0; i < way.nodes.length; i++) {
66880               node = graph.entity(way.nodes[i]);
66881               type = svgPassiveVertex(node, graph, activeID);
66882               end = {
66883                 node: node,
66884                 type: type
66885               };
66886
66887               if (start.type !== undefined) {
66888                 if (start.node.id === activeID || end.node.id === activeID) ; else if (isActiveWay && (start.type === 2 || end.type === 2)) {
66889                   // one adjacent vertex
66890                   pushActive(start, end, i);
66891                 } else if (start.type === 0 && end.type === 0) {
66892                   // both active vertices
66893                   pushActive(start, end, i);
66894                 } else {
66895                   pushPassive(start, end, i);
66896                 }
66897               }
66898
66899               start = end;
66900             }
66901
66902             return features;
66903
66904             function pushActive(start, end, index) {
66905               features.active.push({
66906                 type: 'Feature',
66907                 id: way.id + '-' + index + '-nope',
66908                 properties: {
66909                   nope: true,
66910                   target: true,
66911                   entity: way,
66912                   nodes: [start.node, end.node],
66913                   index: index
66914                 },
66915                 geometry: {
66916                   type: 'LineString',
66917                   coordinates: [start.node.loc, end.node.loc]
66918                 }
66919               });
66920             }
66921
66922             function pushPassive(start, end, index) {
66923               features.passive.push({
66924                 type: 'Feature',
66925                 id: way.id + '-' + index,
66926                 properties: {
66927                   target: true,
66928                   entity: way,
66929                   nodes: [start.node, end.node],
66930                   index: index
66931                 },
66932                 geometry: {
66933                   type: 'LineString',
66934                   coordinates: [start.node.loc, end.node.loc]
66935                 }
66936               });
66937             }
66938           }
66939         }
66940
66941         function svgTagClasses() {
66942           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'];
66943           var statuses = [// nonexistent, might be built
66944           'proposed', 'planned', // under maintentance or between groundbreaking and opening
66945           'construction', // existent but not functional
66946           'disused', // dilapidated to nonexistent
66947           'abandoned', // nonexistent, still may appear in imagery
66948           'dismantled', 'razed', 'demolished', 'obliterated', // existent occasionally, e.g. stormwater drainage basin
66949           'intermittent'];
66950           var secondaries = ['oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier', 'surface', 'tracktype', 'footway', 'crossing', 'service', 'sport', 'public_transport', 'location', 'parking', 'golf', 'type', 'leisure', 'man_made', 'indoor'];
66951
66952           var _tags = function _tags(entity) {
66953             return entity.tags;
66954           };
66955
66956           var tagClasses = function tagClasses(selection) {
66957             selection.each(function tagClassesEach(entity) {
66958               var value = this.className;
66959
66960               if (value.baseVal !== undefined) {
66961                 value = value.baseVal;
66962               }
66963
66964               var t = _tags(entity);
66965
66966               var computed = tagClasses.getClassesString(t, value);
66967
66968               if (computed !== value) {
66969                 select(this).attr('class', computed);
66970               }
66971             });
66972           };
66973
66974           tagClasses.getClassesString = function (t, value) {
66975             var primary, status;
66976             var i, j, k, v; // in some situations we want to render perimeter strokes a certain way
66977
66978             var overrideGeometry;
66979
66980             if (/\bstroke\b/.test(value)) {
66981               if (!!t.barrier && t.barrier !== 'no') {
66982                 overrideGeometry = 'line';
66983               }
66984             } // preserve base classes (nothing with `tag-`)
66985
66986
66987             var classes = value.trim().split(/\s+/).filter(function (klass) {
66988               return klass.length && !/^tag-/.test(klass);
66989             }).map(function (klass) {
66990               // special overrides for some perimeter strokes
66991               return klass === 'line' || klass === 'area' ? overrideGeometry || klass : klass;
66992             }); // pick at most one primary classification tag..
66993
66994             for (i = 0; i < primaries.length; i++) {
66995               k = primaries[i];
66996               v = t[k];
66997               if (!v || v === 'no') continue;
66998
66999               if (k === 'piste:type') {
67000                 // avoid a ':' in the class name
67001                 k = 'piste';
67002               } else if (k === 'building:part') {
67003                 // avoid a ':' in the class name
67004                 k = 'building_part';
67005               }
67006
67007               primary = k;
67008
67009               if (statuses.indexOf(v) !== -1) {
67010                 // e.g. `railway=abandoned`
67011                 status = v;
67012                 classes.push('tag-' + k);
67013               } else {
67014                 classes.push('tag-' + k);
67015                 classes.push('tag-' + k + '-' + v);
67016               }
67017
67018               break;
67019             }
67020
67021             if (!primary) {
67022               for (i = 0; i < statuses.length; i++) {
67023                 for (j = 0; j < primaries.length; j++) {
67024                   k = statuses[i] + ':' + primaries[j]; // e.g. `demolished:building=yes`
67025
67026                   v = t[k];
67027                   if (!v || v === 'no') continue;
67028                   status = statuses[i];
67029                   break;
67030                 }
67031               }
67032             } // add at most one status tag, only if relates to primary tag..
67033
67034
67035             if (!status) {
67036               for (i = 0; i < statuses.length; i++) {
67037                 k = statuses[i];
67038                 v = t[k];
67039                 if (!v || v === 'no') continue;
67040
67041                 if (v === 'yes') {
67042                   // e.g. `railway=rail + abandoned=yes`
67043                   status = k;
67044                 } else if (primary && primary === v) {
67045                   // e.g. `railway=rail + abandoned=railway`
67046                   status = k;
67047                 } else if (!primary && primaries.indexOf(v) !== -1) {
67048                   // e.g. `abandoned=railway`
67049                   status = k;
67050                   primary = v;
67051                   classes.push('tag-' + v);
67052                 } // else ignore e.g.  `highway=path + abandoned=railway`
67053
67054
67055                 if (status) break;
67056               }
67057             }
67058
67059             if (status) {
67060               classes.push('tag-status');
67061               classes.push('tag-status-' + status);
67062             } // add any secondary tags
67063
67064
67065             for (i = 0; i < secondaries.length; i++) {
67066               k = secondaries[i];
67067               v = t[k];
67068               if (!v || v === 'no' || k === primary) continue;
67069               classes.push('tag-' + k);
67070               classes.push('tag-' + k + '-' + v);
67071             } // For highways, look for surface tagging..
67072
67073
67074             if (primary === 'highway' && !osmPathHighwayTagValues[t.highway] || primary === 'aeroway') {
67075               var surface = t.highway === 'track' ? 'unpaved' : 'paved';
67076
67077               for (k in t) {
67078                 v = t[k];
67079
67080                 if (k in osmPavedTags) {
67081                   surface = osmPavedTags[k][v] ? 'paved' : 'unpaved';
67082                 }
67083
67084                 if (k in osmSemipavedTags && !!osmSemipavedTags[k][v]) {
67085                   surface = 'semipaved';
67086                 }
67087               }
67088
67089               classes.push('tag-' + surface);
67090             } // If this is a wikidata-tagged item, add a class for that..
67091
67092
67093             if (t.wikidata || t['brand:wikidata']) {
67094               classes.push('tag-wikidata');
67095             }
67096
67097             return classes.join(' ').trim();
67098           };
67099
67100           tagClasses.tags = function (val) {
67101             if (!arguments.length) return _tags;
67102             _tags = val;
67103             return tagClasses;
67104           };
67105
67106           return tagClasses;
67107         }
67108
67109         // Patterns only work in Firefox when set directly on element.
67110         // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
67111         var patterns = {
67112           // tag - pattern name
67113           // -or-
67114           // tag - value - pattern name
67115           // -or-
67116           // tag - value - rules (optional tag-values, pattern name)
67117           // (matches earlier rules first, so fallback should be last entry)
67118           amenity: {
67119             grave_yard: 'cemetery',
67120             fountain: 'water_standing'
67121           },
67122           landuse: {
67123             cemetery: [{
67124               religion: 'christian',
67125               pattern: 'cemetery_christian'
67126             }, {
67127               religion: 'buddhist',
67128               pattern: 'cemetery_buddhist'
67129             }, {
67130               religion: 'muslim',
67131               pattern: 'cemetery_muslim'
67132             }, {
67133               religion: 'jewish',
67134               pattern: 'cemetery_jewish'
67135             }, {
67136               pattern: 'cemetery'
67137             }],
67138             construction: 'construction',
67139             farmland: 'farmland',
67140             farmyard: 'farmyard',
67141             forest: [{
67142               leaf_type: 'broadleaved',
67143               pattern: 'forest_broadleaved'
67144             }, {
67145               leaf_type: 'needleleaved',
67146               pattern: 'forest_needleleaved'
67147             }, {
67148               leaf_type: 'leafless',
67149               pattern: 'forest_leafless'
67150             }, {
67151               pattern: 'forest'
67152             } // same as 'leaf_type:mixed'
67153             ],
67154             grave_yard: 'cemetery',
67155             grass: [{
67156               golf: 'green',
67157               pattern: 'golf_green'
67158             }, {
67159               pattern: 'grass'
67160             }],
67161             landfill: 'landfill',
67162             meadow: 'meadow',
67163             military: 'construction',
67164             orchard: 'orchard',
67165             quarry: 'quarry',
67166             vineyard: 'vineyard'
67167           },
67168           natural: {
67169             beach: 'beach',
67170             grassland: 'grass',
67171             sand: 'beach',
67172             scrub: 'scrub',
67173             water: [{
67174               water: 'pond',
67175               pattern: 'pond'
67176             }, {
67177               water: 'reservoir',
67178               pattern: 'water_standing'
67179             }, {
67180               pattern: 'waves'
67181             }],
67182             wetland: [{
67183               wetland: 'marsh',
67184               pattern: 'wetland_marsh'
67185             }, {
67186               wetland: 'swamp',
67187               pattern: 'wetland_swamp'
67188             }, {
67189               wetland: 'bog',
67190               pattern: 'wetland_bog'
67191             }, {
67192               wetland: 'reedbed',
67193               pattern: 'wetland_reedbed'
67194             }, {
67195               pattern: 'wetland'
67196             }],
67197             wood: [{
67198               leaf_type: 'broadleaved',
67199               pattern: 'forest_broadleaved'
67200             }, {
67201               leaf_type: 'needleleaved',
67202               pattern: 'forest_needleleaved'
67203             }, {
67204               leaf_type: 'leafless',
67205               pattern: 'forest_leafless'
67206             }, {
67207               pattern: 'forest'
67208             } // same as 'leaf_type:mixed'
67209             ]
67210           },
67211           traffic_calming: {
67212             island: [{
67213               surface: 'grass',
67214               pattern: 'grass'
67215             }],
67216             chicane: [{
67217               surface: 'grass',
67218               pattern: 'grass'
67219             }],
67220             choker: [{
67221               surface: 'grass',
67222               pattern: 'grass'
67223             }]
67224           }
67225         };
67226         function svgTagPattern(tags) {
67227           // Skip pattern filling if this is a building (buildings don't get patterns applied)
67228           if (tags.building && tags.building !== 'no') {
67229             return null;
67230           }
67231
67232           for (var tag in patterns) {
67233             var entityValue = tags[tag];
67234             if (!entityValue) continue;
67235
67236             if (typeof patterns[tag] === 'string') {
67237               // extra short syntax (just tag) - pattern name
67238               return 'pattern-' + patterns[tag];
67239             } else {
67240               var values = patterns[tag];
67241
67242               for (var value in values) {
67243                 if (entityValue !== value) continue;
67244                 var rules = values[value];
67245
67246                 if (typeof rules === 'string') {
67247                   // short syntax - pattern name
67248                   return 'pattern-' + rules;
67249                 } // long syntax - rule array
67250
67251
67252                 for (var ruleKey in rules) {
67253                   var rule = rules[ruleKey];
67254                   var pass = true;
67255
67256                   for (var criterion in rule) {
67257                     if (criterion !== 'pattern') {
67258                       // reserved for pattern name
67259                       // The only rule is a required tag-value pair
67260                       var v = tags[criterion];
67261
67262                       if (!v || v !== rule[criterion]) {
67263                         pass = false;
67264                         break;
67265                       }
67266                     }
67267                   }
67268
67269                   if (pass) {
67270                     return 'pattern-' + rule.pattern;
67271                   }
67272                 }
67273               }
67274             }
67275           }
67276
67277           return null;
67278         }
67279
67280         function svgAreas(projection, context) {
67281           function getPatternStyle(tags) {
67282             var imageID = svgTagPattern(tags);
67283
67284             if (imageID) {
67285               return 'url("#ideditor-' + imageID + '")';
67286             }
67287
67288             return '';
67289           }
67290
67291           function drawTargets(selection, graph, entities, filter) {
67292             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
67293             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
67294             var getPath = svgPath(projection).geojson;
67295             var activeID = context.activeID();
67296             var base = context.history().base(); // The targets and nopes will be MultiLineString sub-segments of the ways
67297
67298             var data = {
67299               targets: [],
67300               nopes: []
67301             };
67302             entities.forEach(function (way) {
67303               var features = svgSegmentWay(way, graph, activeID);
67304               data.targets.push.apply(data.targets, features.passive);
67305               data.nopes.push.apply(data.nopes, features.active);
67306             }); // Targets allow hover and vertex snapping
67307
67308             var targetData = data.targets.filter(getPath);
67309             var targets = selection.selectAll('.area.target-allowed').filter(function (d) {
67310               return filter(d.properties.entity);
67311             }).data(targetData, function key(d) {
67312               return d.id;
67313             }); // exit
67314
67315             targets.exit().remove();
67316
67317             var segmentWasEdited = function segmentWasEdited(d) {
67318               var wayID = d.properties.entity.id; // if the whole line was edited, don't draw segment changes
67319
67320               if (!base.entities[wayID] || !fastDeepEqual(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
67321                 return false;
67322               }
67323
67324               return d.properties.nodes.some(function (n) {
67325                 return !base.entities[n.id] || !fastDeepEqual(graph.entities[n.id].loc, base.entities[n.id].loc);
67326               });
67327             }; // enter/update
67328
67329
67330             targets.enter().append('path').merge(targets).attr('d', getPath).attr('class', function (d) {
67331               return 'way area target target-allowed ' + targetClass + d.id;
67332             }).classed('segment-edited', segmentWasEdited); // NOPE
67333
67334             var nopeData = data.nopes.filter(getPath);
67335             var nopes = selection.selectAll('.area.target-nope').filter(function (d) {
67336               return filter(d.properties.entity);
67337             }).data(nopeData, function key(d) {
67338               return d.id;
67339             }); // exit
67340
67341             nopes.exit().remove(); // enter/update
67342
67343             nopes.enter().append('path').merge(nopes).attr('d', getPath).attr('class', function (d) {
67344               return 'way area target target-nope ' + nopeClass + d.id;
67345             }).classed('segment-edited', segmentWasEdited);
67346           }
67347
67348           function drawAreas(selection, graph, entities, filter) {
67349             var path = svgPath(projection, graph, true);
67350             var areas = {};
67351             var multipolygon;
67352             var base = context.history().base();
67353
67354             for (var i = 0; i < entities.length; i++) {
67355               var entity = entities[i];
67356               if (entity.geometry(graph) !== 'area') continue;
67357               multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
67358
67359               if (multipolygon) {
67360                 areas[multipolygon.id] = {
67361                   entity: multipolygon.mergeTags(entity.tags),
67362                   area: Math.abs(entity.area(graph))
67363                 };
67364               } else if (!areas[entity.id]) {
67365                 areas[entity.id] = {
67366                   entity: entity,
67367                   area: Math.abs(entity.area(graph))
67368                 };
67369               }
67370             }
67371
67372             var fills = Object.values(areas).filter(function hasPath(a) {
67373               return path(a.entity);
67374             });
67375             fills.sort(function areaSort(a, b) {
67376               return b.area - a.area;
67377             });
67378             fills = fills.map(function (a) {
67379               return a.entity;
67380             });
67381             var strokes = fills.filter(function (area) {
67382               return area.type === 'way';
67383             });
67384             var data = {
67385               clip: fills,
67386               shadow: strokes,
67387               stroke: strokes,
67388               fill: fills
67389             };
67390             var clipPaths = context.surface().selectAll('defs').selectAll('.clipPath-osm').filter(filter).data(data.clip, osmEntity.key);
67391             clipPaths.exit().remove();
67392             var clipPathsEnter = clipPaths.enter().append('clipPath').attr('class', 'clipPath-osm').attr('id', function (entity) {
67393               return 'ideditor-' + entity.id + '-clippath';
67394             });
67395             clipPathsEnter.append('path');
67396             clipPaths.merge(clipPathsEnter).selectAll('path').attr('d', path);
67397             var drawLayer = selection.selectAll('.layer-osm.areas');
67398             var touchLayer = selection.selectAll('.layer-touch.areas'); // Draw areas..
67399
67400             var areagroup = drawLayer.selectAll('g.areagroup').data(['fill', 'shadow', 'stroke']);
67401             areagroup = areagroup.enter().append('g').attr('class', function (d) {
67402               return 'areagroup area-' + d;
67403             }).merge(areagroup);
67404             var paths = areagroup.selectAll('path').filter(filter).data(function (layer) {
67405               return data[layer];
67406             }, osmEntity.key);
67407             paths.exit().remove();
67408             var fillpaths = selection.selectAll('.area-fill path.area').nodes();
67409             var bisect = d3_bisector(function (node) {
67410               return -node.__data__.area(graph);
67411             }).left;
67412
67413             function sortedByArea(entity) {
67414               if (this._parent.__data__ === 'fill') {
67415                 return fillpaths[bisect(fillpaths, -entity.area(graph))];
67416               }
67417             }
67418
67419             paths = paths.enter().insert('path', sortedByArea).merge(paths).each(function (entity) {
67420               var layer = this.parentNode.__data__;
67421               this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
67422
67423               if (layer === 'fill') {
67424                 this.setAttribute('clip-path', 'url(#ideditor-' + entity.id + '-clippath)');
67425                 this.style.fill = this.style.stroke = getPatternStyle(entity.tags);
67426               }
67427             }).classed('added', function (d) {
67428               return !base.entities[d.id];
67429             }).classed('geometry-edited', function (d) {
67430               return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].nodes, base.entities[d.id].nodes);
67431             }).classed('retagged', function (d) {
67432               return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
67433             }).call(svgTagClasses()).attr('d', path); // Draw touch targets..
67434
67435             touchLayer.call(drawTargets, graph, data.stroke, filter);
67436           }
67437
67438           return drawAreas;
67439         }
67440
67441         //[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]
67442         //[4a]          NameChar           ::=          NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
67443         //[5]           Name       ::=          NameStartChar (NameChar)*
67444         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
67445
67446         var nameChar = new RegExp("[\\-\\.0-9" + nameStartChar.source.slice(1, -1) + "\\u00B7\\u0300-\\u036F\\u203F-\\u2040]");
67447         var tagNamePattern = new RegExp('^' + nameStartChar.source + nameChar.source + '*(?:\:' + nameStartChar.source + nameChar.source + '*)?$'); //var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
67448         //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(',')
67449         //S_TAG,        S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
67450         //S_ATTR_SPACE, S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
67451
67452         var S_TAG = 0; //tag name offerring
67453
67454         var S_ATTR = 1; //attr name offerring 
67455
67456         var S_ATTR_SPACE = 2; //attr name end and space offer
67457
67458         var S_EQ = 3; //=space?
67459
67460         var S_ATTR_NOQUOT_VALUE = 4; //attr value(no quot value only)
67461
67462         var S_ATTR_END = 5; //attr value end and no space(quot end)
67463
67464         var S_TAG_SPACE = 6; //(attr value end || tag end ) && (space offer)
67465
67466         var S_TAG_CLOSE = 7; //closed el<el />
67467
67468         function XMLReader() {}
67469
67470         XMLReader.prototype = {
67471           parse: function parse(source, defaultNSMap, entityMap) {
67472             var domBuilder = this.domBuilder;
67473             domBuilder.startDocument();
67474
67475             _copy(defaultNSMap, defaultNSMap = {});
67476
67477             _parse(source, defaultNSMap, entityMap, domBuilder, this.errorHandler);
67478
67479             domBuilder.endDocument();
67480           }
67481         };
67482
67483         function _parse(source, defaultNSMapCopy, entityMap, domBuilder, errorHandler) {
67484           function fixedFromCharCode(code) {
67485             // String.prototype.fromCharCode does not supports
67486             // > 2 bytes unicode chars directly
67487             if (code > 0xffff) {
67488               code -= 0x10000;
67489               var surrogate1 = 0xd800 + (code >> 10),
67490                   surrogate2 = 0xdc00 + (code & 0x3ff);
67491               return String.fromCharCode(surrogate1, surrogate2);
67492             } else {
67493               return String.fromCharCode(code);
67494             }
67495           }
67496
67497           function entityReplacer(a) {
67498             var k = a.slice(1, -1);
67499
67500             if (k in entityMap) {
67501               return entityMap[k];
67502             } else if (k.charAt(0) === '#') {
67503               return fixedFromCharCode(parseInt(k.substr(1).replace('x', '0x')));
67504             } else {
67505               errorHandler.error('entity not found:' + a);
67506               return a;
67507             }
67508           }
67509
67510           function appendText(end) {
67511             //has some bugs
67512             if (end > start) {
67513               var xt = source.substring(start, end).replace(/&#?\w+;/g, entityReplacer);
67514               locator && position(start);
67515               domBuilder.characters(xt, 0, end - start);
67516               start = end;
67517             }
67518           }
67519
67520           function position(p, m) {
67521             while (p >= lineEnd && (m = linePattern.exec(source))) {
67522               lineStart = m.index;
67523               lineEnd = lineStart + m[0].length;
67524               locator.lineNumber++; //console.log('line++:',locator,startPos,endPos)
67525             }
67526
67527             locator.columnNumber = p - lineStart + 1;
67528           }
67529
67530           var lineStart = 0;
67531           var lineEnd = 0;
67532           var linePattern = /.*(?:\r\n?|\n)|.*$/g;
67533           var locator = domBuilder.locator;
67534           var parseStack = [{
67535             currentNSMap: defaultNSMapCopy
67536           }];
67537           var closeMap = {};
67538           var start = 0;
67539
67540           while (true) {
67541             try {
67542               var tagStart = source.indexOf('<', start);
67543
67544               if (tagStart < 0) {
67545                 if (!source.substr(start).match(/^\s*$/)) {
67546                   var doc = domBuilder.doc;
67547                   var text = doc.createTextNode(source.substr(start));
67548                   doc.appendChild(text);
67549                   domBuilder.currentElement = text;
67550                 }
67551
67552                 return;
67553               }
67554
67555               if (tagStart > start) {
67556                 appendText(tagStart);
67557               }
67558
67559               switch (source.charAt(tagStart + 1)) {
67560                 case '/':
67561                   var end = source.indexOf('>', tagStart + 3);
67562                   var tagName = source.substring(tagStart + 2, end);
67563                   var config = parseStack.pop();
67564
67565                   if (end < 0) {
67566                     tagName = source.substring(tagStart + 2).replace(/[\s<].*/, ''); //console.error('#@@@@@@'+tagName)
67567
67568                     errorHandler.error("end tag name: " + tagName + ' is not complete:' + config.tagName);
67569                     end = tagStart + 1 + tagName.length;
67570                   } else if (tagName.match(/\s</)) {
67571                     tagName = tagName.replace(/[\s<].*/, '');
67572                     errorHandler.error("end tag name: " + tagName + ' maybe not complete');
67573                     end = tagStart + 1 + tagName.length;
67574                   } //console.error(parseStack.length,parseStack)
67575                   //console.error(config);
67576
67577
67578                   var localNSMap = config.localNSMap;
67579                   var endMatch = config.tagName == tagName;
67580                   var endIgnoreCaseMach = endMatch || config.tagName && config.tagName.toLowerCase() == tagName.toLowerCase();
67581
67582                   if (endIgnoreCaseMach) {
67583                     domBuilder.endElement(config.uri, config.localName, tagName);
67584
67585                     if (localNSMap) {
67586                       for (var prefix in localNSMap) {
67587                         domBuilder.endPrefixMapping(prefix);
67588                       }
67589                     }
67590
67591                     if (!endMatch) {
67592                       errorHandler.fatalError("end tag name: " + tagName + ' is not match the current start tagName:' + config.tagName);
67593                     }
67594                   } else {
67595                     parseStack.push(config);
67596                   }
67597
67598                   end++;
67599                   break;
67600                 // end elment
67601
67602                 case '?':
67603                   // <?...?>
67604                   locator && position(tagStart);
67605                   end = parseInstruction(source, tagStart, domBuilder);
67606                   break;
67607
67608                 case '!':
67609                   // <!doctype,<![CDATA,<!--
67610                   locator && position(tagStart);
67611                   end = parseDCC(source, tagStart, domBuilder, errorHandler);
67612                   break;
67613
67614                 default:
67615                   locator && position(tagStart);
67616                   var el = new ElementAttributes();
67617                   var currentNSMap = parseStack[parseStack.length - 1].currentNSMap; //elStartEnd
67618
67619                   var end = parseElementStartPart(source, tagStart, el, currentNSMap, entityReplacer, errorHandler);
67620                   var len = el.length;
67621
67622                   if (!el.closed && fixSelfClosed(source, end, el.tagName, closeMap)) {
67623                     el.closed = true;
67624
67625                     if (!entityMap.nbsp) {
67626                       errorHandler.warning('unclosed xml attribute');
67627                     }
67628                   }
67629
67630                   if (locator && len) {
67631                     var locator2 = copyLocator(locator, {}); //try{//attribute position fixed
67632
67633                     for (var i = 0; i < len; i++) {
67634                       var a = el[i];
67635                       position(a.offset);
67636                       a.locator = copyLocator(locator, {});
67637                     } //}catch(e){console.error('@@@@@'+e)}
67638
67639
67640                     domBuilder.locator = locator2;
67641
67642                     if (appendElement(el, domBuilder, currentNSMap)) {
67643                       parseStack.push(el);
67644                     }
67645
67646                     domBuilder.locator = locator;
67647                   } else {
67648                     if (appendElement(el, domBuilder, currentNSMap)) {
67649                       parseStack.push(el);
67650                     }
67651                   }
67652
67653                   if (el.uri === 'http://www.w3.org/1999/xhtml' && !el.closed) {
67654                     end = parseHtmlSpecialContent(source, end, el.tagName, entityReplacer, domBuilder);
67655                   } else {
67656                     end++;
67657                   }
67658
67659               }
67660             } catch (e) {
67661               errorHandler.error('element parse error: ' + e); //errorHandler.error('element parse error: '+e);
67662
67663               end = -1; //throw e;
67664             }
67665
67666             if (end > start) {
67667               start = end;
67668             } else {
67669               //TODO: 这里有可能sax回退,有位置错误风险
67670               appendText(Math.max(tagStart, start) + 1);
67671             }
67672           }
67673         }
67674
67675         function copyLocator(f, t) {
67676           t.lineNumber = f.lineNumber;
67677           t.columnNumber = f.columnNumber;
67678           return t;
67679         }
67680         /**
67681          * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
67682          * @return end of the elementStartPart(end of elementEndPart for selfClosed el)
67683          */
67684
67685
67686         function parseElementStartPart(source, start, el, currentNSMap, entityReplacer, errorHandler) {
67687           var attrName;
67688           var value;
67689           var p = ++start;
67690           var s = S_TAG; //status
67691
67692           while (true) {
67693             var c = source.charAt(p);
67694
67695             switch (c) {
67696               case '=':
67697                 if (s === S_ATTR) {
67698                   //attrName
67699                   attrName = source.slice(start, p);
67700                   s = S_EQ;
67701                 } else if (s === S_ATTR_SPACE) {
67702                   s = S_EQ;
67703                 } else {
67704                   //fatalError: equal must after attrName or space after attrName
67705                   throw new Error('attribute equal must after attrName');
67706                 }
67707
67708                 break;
67709
67710               case '\'':
67711               case '"':
67712                 if (s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE
67713                 ) {
67714                     //equal
67715                     if (s === S_ATTR) {
67716                       errorHandler.warning('attribute value must after "="');
67717                       attrName = source.slice(start, p);
67718                     }
67719
67720                     start = p + 1;
67721                     p = source.indexOf(c, start);
67722
67723                     if (p > 0) {
67724                       value = source.slice(start, p).replace(/&#?\w+;/g, entityReplacer);
67725                       el.add(attrName, value, start - 1);
67726                       s = S_ATTR_END;
67727                     } else {
67728                       //fatalError: no end quot match
67729                       throw new Error('attribute value no end \'' + c + '\' match');
67730                     }
67731                   } else if (s == S_ATTR_NOQUOT_VALUE) {
67732                   value = source.slice(start, p).replace(/&#?\w+;/g, entityReplacer); //console.log(attrName,value,start,p)
67733
67734                   el.add(attrName, value, start); //console.dir(el)
67735
67736                   errorHandler.warning('attribute "' + attrName + '" missed start quot(' + c + ')!!');
67737                   start = p + 1;
67738                   s = S_ATTR_END;
67739                 } else {
67740                   //fatalError: no equal before
67741                   throw new Error('attribute value must after "="');
67742                 }
67743
67744                 break;
67745
67746               case '/':
67747                 switch (s) {
67748                   case S_TAG:
67749                     el.setTagName(source.slice(start, p));
67750
67751                   case S_ATTR_END:
67752                   case S_TAG_SPACE:
67753                   case S_TAG_CLOSE:
67754                     s = S_TAG_CLOSE;
67755                     el.closed = true;
67756
67757                   case S_ATTR_NOQUOT_VALUE:
67758                   case S_ATTR:
67759                   case S_ATTR_SPACE:
67760                     break;
67761                   //case S_EQ:
67762
67763                   default:
67764                     throw new Error("attribute invalid close char('/')");
67765                 }
67766
67767                 break;
67768
67769               case '':
67770                 //end document
67771                 //throw new Error('unexpected end of input')
67772                 errorHandler.error('unexpected end of input');
67773
67774                 if (s == S_TAG) {
67775                   el.setTagName(source.slice(start, p));
67776                 }
67777
67778                 return p;
67779
67780               case '>':
67781                 switch (s) {
67782                   case S_TAG:
67783                     el.setTagName(source.slice(start, p));
67784
67785                   case S_ATTR_END:
67786                   case S_TAG_SPACE:
67787                   case S_TAG_CLOSE:
67788                     break;
67789                   //normal
67790
67791                   case S_ATTR_NOQUOT_VALUE: //Compatible state
67792
67793                   case S_ATTR:
67794                     value = source.slice(start, p);
67795
67796                     if (value.slice(-1) === '/') {
67797                       el.closed = true;
67798                       value = value.slice(0, -1);
67799                     }
67800
67801                   case S_ATTR_SPACE:
67802                     if (s === S_ATTR_SPACE) {
67803                       value = attrName;
67804                     }
67805
67806                     if (s == S_ATTR_NOQUOT_VALUE) {
67807                       errorHandler.warning('attribute "' + value + '" missed quot(")!!');
67808                       el.add(attrName, value.replace(/&#?\w+;/g, entityReplacer), start);
67809                     } else {
67810                       if (currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !value.match(/^(?:disabled|checked|selected)$/i)) {
67811                         errorHandler.warning('attribute "' + value + '" missed value!! "' + value + '" instead!!');
67812                       }
67813
67814                       el.add(value, value, start);
67815                     }
67816
67817                     break;
67818
67819                   case S_EQ:
67820                     throw new Error('attribute value missed!!');
67821                 } //                    console.log(tagName,tagNamePattern,tagNamePattern.test(tagName))
67822
67823
67824                 return p;
67825
67826               /*xml space '\x20' | #x9 | #xD | #xA; */
67827
67828               case "\x80":
67829                 c = ' ';
67830
67831               default:
67832                 if (c <= ' ') {
67833                   //space
67834                   switch (s) {
67835                     case S_TAG:
67836                       el.setTagName(source.slice(start, p)); //tagName
67837
67838                       s = S_TAG_SPACE;
67839                       break;
67840
67841                     case S_ATTR:
67842                       attrName = source.slice(start, p);
67843                       s = S_ATTR_SPACE;
67844                       break;
67845
67846                     case S_ATTR_NOQUOT_VALUE:
67847                       var value = source.slice(start, p).replace(/&#?\w+;/g, entityReplacer);
67848                       errorHandler.warning('attribute "' + value + '" missed quot(")!!');
67849                       el.add(attrName, value, start);
67850
67851                     case S_ATTR_END:
67852                       s = S_TAG_SPACE;
67853                       break;
67854                     //case S_TAG_SPACE:
67855                     //case S_EQ:
67856                     //case S_ATTR_SPACE:
67857                     //  void();break;
67858                     //case S_TAG_CLOSE:
67859                     //ignore warning
67860                   }
67861                 } else {
67862                   //not space
67863                   //S_TAG,      S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
67864                   //S_ATTR_SPACE,       S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
67865                   switch (s) {
67866                     //case S_TAG:void();break;
67867                     //case S_ATTR:void();break;
67868                     //case S_ATTR_NOQUOT_VALUE:void();break;
67869                     case S_ATTR_SPACE:
67870                       var tagName = el.tagName;
67871
67872                       if (currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !attrName.match(/^(?:disabled|checked|selected)$/i)) {
67873                         errorHandler.warning('attribute "' + attrName + '" missed value!! "' + attrName + '" instead2!!');
67874                       }
67875
67876                       el.add(attrName, attrName, start);
67877                       start = p;
67878                       s = S_ATTR;
67879                       break;
67880
67881                     case S_ATTR_END:
67882                       errorHandler.warning('attribute space is required"' + attrName + '"!!');
67883
67884                     case S_TAG_SPACE:
67885                       s = S_ATTR;
67886                       start = p;
67887                       break;
67888
67889                     case S_EQ:
67890                       s = S_ATTR_NOQUOT_VALUE;
67891                       start = p;
67892                       break;
67893
67894                     case S_TAG_CLOSE:
67895                       throw new Error("elements closed character '/' and '>' must be connected to");
67896                   }
67897                 }
67898
67899             } //end outer switch
67900             //console.log('p++',p)
67901
67902
67903             p++;
67904           }
67905         }
67906         /**
67907          * @return true if has new namespace define
67908          */
67909
67910
67911         function appendElement(el, domBuilder, currentNSMap) {
67912           var tagName = el.tagName;
67913           var localNSMap = null; //var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
67914
67915           var i = el.length;
67916
67917           while (i--) {
67918             var a = el[i];
67919             var qName = a.qName;
67920             var value = a.value;
67921             var nsp = qName.indexOf(':');
67922
67923             if (nsp > 0) {
67924               var prefix = a.prefix = qName.slice(0, nsp);
67925               var localName = qName.slice(nsp + 1);
67926               var nsPrefix = prefix === 'xmlns' && localName;
67927             } else {
67928               localName = qName;
67929               prefix = null;
67930               nsPrefix = qName === 'xmlns' && '';
67931             } //can not set prefix,because prefix !== ''
67932
67933
67934             a.localName = localName; //prefix == null for no ns prefix attribute 
67935
67936             if (nsPrefix !== false) {
67937               //hack!!
67938               if (localNSMap == null) {
67939                 localNSMap = {}; //console.log(currentNSMap,0)
67940
67941                 _copy(currentNSMap, currentNSMap = {}); //console.log(currentNSMap,1)
67942
67943               }
67944
67945               currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
67946               a.uri = 'http://www.w3.org/2000/xmlns/';
67947               domBuilder.startPrefixMapping(nsPrefix, value);
67948             }
67949           }
67950
67951           var i = el.length;
67952
67953           while (i--) {
67954             a = el[i];
67955             var prefix = a.prefix;
67956
67957             if (prefix) {
67958               //no prefix attribute has no namespace
67959               if (prefix === 'xml') {
67960                 a.uri = 'http://www.w3.org/XML/1998/namespace';
67961               }
67962
67963               if (prefix !== 'xmlns') {
67964                 a.uri = currentNSMap[prefix || '']; //{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}
67965               }
67966             }
67967           }
67968
67969           var nsp = tagName.indexOf(':');
67970
67971           if (nsp > 0) {
67972             prefix = el.prefix = tagName.slice(0, nsp);
67973             localName = el.localName = tagName.slice(nsp + 1);
67974           } else {
67975             prefix = null; //important!!
67976
67977             localName = el.localName = tagName;
67978           } //no prefix element has default namespace
67979
67980
67981           var ns = el.uri = currentNSMap[prefix || ''];
67982           domBuilder.startElement(ns, localName, tagName, el); //endPrefixMapping and startPrefixMapping have not any help for dom builder
67983           //localNSMap = null
67984
67985           if (el.closed) {
67986             domBuilder.endElement(ns, localName, tagName);
67987
67988             if (localNSMap) {
67989               for (prefix in localNSMap) {
67990                 domBuilder.endPrefixMapping(prefix);
67991               }
67992             }
67993           } else {
67994             el.currentNSMap = currentNSMap;
67995             el.localNSMap = localNSMap; //parseStack.push(el);
67996
67997             return true;
67998           }
67999         }
68000
68001         function parseHtmlSpecialContent(source, elStartEnd, tagName, entityReplacer, domBuilder) {
68002           if (/^(?:script|textarea)$/i.test(tagName)) {
68003             var elEndStart = source.indexOf('</' + tagName + '>', elStartEnd);
68004             var text = source.substring(elStartEnd + 1, elEndStart);
68005
68006             if (/[&<]/.test(text)) {
68007               if (/^script$/i.test(tagName)) {
68008                 //if(!/\]\]>/.test(text)){
68009                 //lexHandler.startCDATA();
68010                 domBuilder.characters(text, 0, text.length); //lexHandler.endCDATA();
68011
68012                 return elEndStart; //}
68013               } //}else{//text area
68014
68015
68016               text = text.replace(/&#?\w+;/g, entityReplacer);
68017               domBuilder.characters(text, 0, text.length);
68018               return elEndStart; //}
68019             }
68020           }
68021
68022           return elStartEnd + 1;
68023         }
68024
68025         function fixSelfClosed(source, elStartEnd, tagName, closeMap) {
68026           //if(tagName in closeMap){
68027           var pos = closeMap[tagName];
68028
68029           if (pos == null) {
68030             //console.log(tagName)
68031             pos = source.lastIndexOf('</' + tagName + '>');
68032
68033             if (pos < elStartEnd) {
68034               //忘记闭合
68035               pos = source.lastIndexOf('</' + tagName);
68036             }
68037
68038             closeMap[tagName] = pos;
68039           }
68040
68041           return pos < elStartEnd; //} 
68042         }
68043
68044         function _copy(source, target) {
68045           for (var n in source) {
68046             target[n] = source[n];
68047           }
68048         }
68049
68050         function parseDCC(source, start, domBuilder, errorHandler) {
68051           //sure start with '<!'
68052           var next = source.charAt(start + 2);
68053
68054           switch (next) {
68055             case '-':
68056               if (source.charAt(start + 3) === '-') {
68057                 var end = source.indexOf('-->', start + 4); //append comment source.substring(4,end)//<!--
68058
68059                 if (end > start) {
68060                   domBuilder.comment(source, start + 4, end - start - 4);
68061                   return end + 3;
68062                 } else {
68063                   errorHandler.error("Unclosed comment");
68064                   return -1;
68065                 }
68066               } else {
68067                 //error
68068                 return -1;
68069               }
68070
68071             default:
68072               if (source.substr(start + 3, 6) == 'CDATA[') {
68073                 var end = source.indexOf(']]>', start + 9);
68074                 domBuilder.startCDATA();
68075                 domBuilder.characters(source, start + 9, end - start - 9);
68076                 domBuilder.endCDATA();
68077                 return end + 3;
68078               } //<!DOCTYPE
68079               //startDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId) 
68080
68081
68082               var matchs = split$1(source, start);
68083               var len = matchs.length;
68084
68085               if (len > 1 && /!doctype/i.test(matchs[0][0])) {
68086                 var name = matchs[1][0];
68087                 var pubid = len > 3 && /^public$/i.test(matchs[2][0]) && matchs[3][0];
68088                 var sysid = len > 4 && matchs[4][0];
68089                 var lastMatch = matchs[len - 1];
68090                 domBuilder.startDTD(name, pubid && pubid.replace(/^(['"])(.*?)\1$/, '$2'), sysid && sysid.replace(/^(['"])(.*?)\1$/, '$2'));
68091                 domBuilder.endDTD();
68092                 return lastMatch.index + lastMatch[0].length;
68093               }
68094
68095           }
68096
68097           return -1;
68098         }
68099
68100         function parseInstruction(source, start, domBuilder) {
68101           var end = source.indexOf('?>', start);
68102
68103           if (end) {
68104             var match = source.substring(start, end).match(/^<\?(\S*)\s*([\s\S]*?)\s*$/);
68105
68106             if (match) {
68107               var len = match[0].length;
68108               domBuilder.processingInstruction(match[1], match[2]);
68109               return end + 2;
68110             } else {
68111               //error
68112               return -1;
68113             }
68114           }
68115
68116           return -1;
68117         }
68118         /**
68119          * @param source
68120          */
68121
68122
68123         function ElementAttributes(source) {}
68124
68125         ElementAttributes.prototype = {
68126           setTagName: function setTagName(tagName) {
68127             if (!tagNamePattern.test(tagName)) {
68128               throw new Error('invalid tagName:' + tagName);
68129             }
68130
68131             this.tagName = tagName;
68132           },
68133           add: function add(qName, value, offset) {
68134             if (!tagNamePattern.test(qName)) {
68135               throw new Error('invalid attribute:' + qName);
68136             }
68137
68138             this[this.length++] = {
68139               qName: qName,
68140               value: value,
68141               offset: offset
68142             };
68143           },
68144           length: 0,
68145           getLocalName: function getLocalName(i) {
68146             return this[i].localName;
68147           },
68148           getLocator: function getLocator(i) {
68149             return this[i].locator;
68150           },
68151           getQName: function getQName(i) {
68152             return this[i].qName;
68153           },
68154           getURI: function getURI(i) {
68155             return this[i].uri;
68156           },
68157           getValue: function getValue(i) {
68158             return this[i].value;
68159           } //  ,getIndex:function(uri, localName)){
68160           //            if(localName){
68161           //                    
68162           //            }else{
68163           //                    var qName = uri
68164           //            }
68165           //    },
68166           //    getValue:function(){return this.getValue(this.getIndex.apply(this,arguments))},
68167           //    getType:function(uri,localName){}
68168           //    getType:function(i){},
68169
68170         };
68171
68172         function _set_proto_(thiz, parent) {
68173           thiz.__proto__ = parent;
68174           return thiz;
68175         }
68176
68177         if (!(_set_proto_({}, _set_proto_.prototype) instanceof _set_proto_)) {
68178           _set_proto_ = function _set_proto_(thiz, parent) {
68179             function p() {}
68180             p.prototype = parent;
68181             p = new p();
68182
68183             for (parent in thiz) {
68184               p[parent] = thiz[parent];
68185             }
68186
68187             return p;
68188           };
68189         }
68190
68191         function split$1(source, start) {
68192           var match;
68193           var buf = [];
68194           var reg = /'[^']+'|"[^"]+"|[^\s<>\/=]+=?|(\/?\s*>|<)/g;
68195           reg.lastIndex = start;
68196           reg.exec(source); //skip <
68197
68198           while (match = reg.exec(source)) {
68199             buf.push(match);
68200             if (match[1]) return buf;
68201           }
68202         }
68203
68204         var XMLReader_1 = XMLReader;
68205         var sax = {
68206           XMLReader: XMLReader_1
68207         };
68208
68209         /*
68210          * DOM Level 2
68211          * Object DOMException
68212          * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html
68213          * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html
68214          */
68215         function copy$1(src, dest) {
68216           for (var p in src) {
68217             dest[p] = src[p];
68218           }
68219         }
68220         /**
68221         ^\w+\.prototype\.([_\w]+)\s*=\s*((?:.*\{\s*?[\r\n][\s\S]*?^})|\S.*?(?=[;\r\n]));?
68222         ^\w+\.prototype\.([_\w]+)\s*=\s*(\S.*?(?=[;\r\n]));?
68223          */
68224
68225
68226         function _extends(Class, Super) {
68227           var pt = Class.prototype;
68228
68229           if (Object.create) {
68230             var ppt = Object.create(Super.prototype);
68231             pt.__proto__ = ppt;
68232           }
68233
68234           if (!(pt instanceof Super)) {
68235             var t = function t() {};
68236             t.prototype = Super.prototype;
68237             t = new t();
68238             copy$1(pt, t);
68239             Class.prototype = pt = t;
68240           }
68241
68242           if (pt.constructor != Class) {
68243             if (typeof Class != 'function') {
68244               console.error("unknow Class:" + Class);
68245             }
68246
68247             pt.constructor = Class;
68248           }
68249         }
68250
68251         var htmlns = 'http://www.w3.org/1999/xhtml'; // Node Types
68252
68253         var NodeType = {};
68254         var ELEMENT_NODE = NodeType.ELEMENT_NODE = 1;
68255         var ATTRIBUTE_NODE = NodeType.ATTRIBUTE_NODE = 2;
68256         var TEXT_NODE = NodeType.TEXT_NODE = 3;
68257         var CDATA_SECTION_NODE = NodeType.CDATA_SECTION_NODE = 4;
68258         var ENTITY_REFERENCE_NODE = NodeType.ENTITY_REFERENCE_NODE = 5;
68259         var ENTITY_NODE = NodeType.ENTITY_NODE = 6;
68260         var PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7;
68261         var COMMENT_NODE = NodeType.COMMENT_NODE = 8;
68262         var DOCUMENT_NODE = NodeType.DOCUMENT_NODE = 9;
68263         var DOCUMENT_TYPE_NODE = NodeType.DOCUMENT_TYPE_NODE = 10;
68264         var DOCUMENT_FRAGMENT_NODE = NodeType.DOCUMENT_FRAGMENT_NODE = 11;
68265         var NOTATION_NODE = NodeType.NOTATION_NODE = 12; // ExceptionCode
68266
68267         var ExceptionCode = {};
68268         var ExceptionMessage = {};
68269         var INDEX_SIZE_ERR = ExceptionCode.INDEX_SIZE_ERR = (ExceptionMessage[1] = "Index size error", 1);
68270         var DOMSTRING_SIZE_ERR = ExceptionCode.DOMSTRING_SIZE_ERR = (ExceptionMessage[2] = "DOMString size error", 2);
68271         var HIERARCHY_REQUEST_ERR = ExceptionCode.HIERARCHY_REQUEST_ERR = (ExceptionMessage[3] = "Hierarchy request error", 3);
68272         var WRONG_DOCUMENT_ERR = ExceptionCode.WRONG_DOCUMENT_ERR = (ExceptionMessage[4] = "Wrong document", 4);
68273         var INVALID_CHARACTER_ERR = ExceptionCode.INVALID_CHARACTER_ERR = (ExceptionMessage[5] = "Invalid character", 5);
68274         var NO_DATA_ALLOWED_ERR = ExceptionCode.NO_DATA_ALLOWED_ERR = (ExceptionMessage[6] = "No data allowed", 6);
68275         var NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = (ExceptionMessage[7] = "No modification allowed", 7);
68276         var NOT_FOUND_ERR = ExceptionCode.NOT_FOUND_ERR = (ExceptionMessage[8] = "Not found", 8);
68277         var NOT_SUPPORTED_ERR = ExceptionCode.NOT_SUPPORTED_ERR = (ExceptionMessage[9] = "Not supported", 9);
68278         var INUSE_ATTRIBUTE_ERR = ExceptionCode.INUSE_ATTRIBUTE_ERR = (ExceptionMessage[10] = "Attribute in use", 10); //level2
68279
68280         var INVALID_STATE_ERR = ExceptionCode.INVALID_STATE_ERR = (ExceptionMessage[11] = "Invalid state", 11);
68281         var SYNTAX_ERR = ExceptionCode.SYNTAX_ERR = (ExceptionMessage[12] = "Syntax error", 12);
68282         var INVALID_MODIFICATION_ERR = ExceptionCode.INVALID_MODIFICATION_ERR = (ExceptionMessage[13] = "Invalid modification", 13);
68283         var NAMESPACE_ERR = ExceptionCode.NAMESPACE_ERR = (ExceptionMessage[14] = "Invalid namespace", 14);
68284         var INVALID_ACCESS_ERR = ExceptionCode.INVALID_ACCESS_ERR = (ExceptionMessage[15] = "Invalid access", 15);
68285
68286         function DOMException$2(code, message) {
68287           if (message instanceof Error) {
68288             var error = message;
68289           } else {
68290             error = this;
68291             Error.call(this, ExceptionMessage[code]);
68292             this.message = ExceptionMessage[code];
68293             if (Error.captureStackTrace) Error.captureStackTrace(this, DOMException$2);
68294           }
68295
68296           error.code = code;
68297           if (message) this.message = this.message + ": " + message;
68298           return error;
68299         }
68300         DOMException$2.prototype = Error.prototype;
68301         copy$1(ExceptionCode, DOMException$2);
68302         /**
68303          * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177
68304          * 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.
68305          * The items in the NodeList are accessible via an integral index, starting from 0.
68306          */
68307
68308         function NodeList() {}
68309         NodeList.prototype = {
68310           /**
68311            * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive.
68312            * @standard level1
68313            */
68314           length: 0,
68315
68316           /**
68317            * 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.
68318            * @standard level1
68319            * @param index  unsigned long 
68320            *   Index into the collection.
68321            * @return Node
68322            *    The node at the indexth position in the NodeList, or null if that is not a valid index. 
68323            */
68324           item: function item(index) {
68325             return this[index] || null;
68326           },
68327           toString: function toString(isHTML, nodeFilter) {
68328             for (var buf = [], i = 0; i < this.length; i++) {
68329               serializeToString(this[i], buf, isHTML, nodeFilter);
68330             }
68331
68332             return buf.join('');
68333           }
68334         };
68335
68336         function LiveNodeList(node, refresh) {
68337           this._node = node;
68338           this._refresh = refresh;
68339
68340           _updateLiveList(this);
68341         }
68342
68343         function _updateLiveList(list) {
68344           var inc = list._node._inc || list._node.ownerDocument._inc;
68345
68346           if (list._inc != inc) {
68347             var ls = list._refresh(list._node); //console.log(ls.length)
68348
68349
68350             __set__(list, 'length', ls.length);
68351
68352             copy$1(ls, list);
68353             list._inc = inc;
68354           }
68355         }
68356
68357         LiveNodeList.prototype.item = function (i) {
68358           _updateLiveList(this);
68359
68360           return this[i];
68361         };
68362
68363         _extends(LiveNodeList, NodeList);
68364         /**
68365          * 
68366          * 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.
68367          * NamedNodeMap objects in the DOM are live.
68368          * used for attributes or DocumentType entities 
68369          */
68370
68371
68372         function NamedNodeMap() {}
68373
68374         function _findNodeIndex(list, node) {
68375           var i = list.length;
68376
68377           while (i--) {
68378             if (list[i] === node) {
68379               return i;
68380             }
68381           }
68382         }
68383
68384         function _addNamedNode(el, list, newAttr, oldAttr) {
68385           if (oldAttr) {
68386             list[_findNodeIndex(list, oldAttr)] = newAttr;
68387           } else {
68388             list[list.length++] = newAttr;
68389           }
68390
68391           if (el) {
68392             newAttr.ownerElement = el;
68393             var doc = el.ownerDocument;
68394
68395             if (doc) {
68396               oldAttr && _onRemoveAttribute(doc, el, oldAttr);
68397
68398               _onAddAttribute(doc, el, newAttr);
68399             }
68400           }
68401         }
68402
68403         function _removeNamedNode(el, list, attr) {
68404           //console.log('remove attr:'+attr)
68405           var i = _findNodeIndex(list, attr);
68406
68407           if (i >= 0) {
68408             var lastIndex = list.length - 1;
68409
68410             while (i < lastIndex) {
68411               list[i] = list[++i];
68412             }
68413
68414             list.length = lastIndex;
68415
68416             if (el) {
68417               var doc = el.ownerDocument;
68418
68419               if (doc) {
68420                 _onRemoveAttribute(doc, el, attr);
68421
68422                 attr.ownerElement = null;
68423               }
68424             }
68425           } else {
68426             throw DOMException$2(NOT_FOUND_ERR, new Error(el.tagName + '@' + attr));
68427           }
68428         }
68429
68430         NamedNodeMap.prototype = {
68431           length: 0,
68432           item: NodeList.prototype.item,
68433           getNamedItem: function getNamedItem(key) {
68434             //          if(key.indexOf(':')>0 || key == 'xmlns'){
68435             //                  return null;
68436             //          }
68437             //console.log()
68438             var i = this.length;
68439
68440             while (i--) {
68441               var attr = this[i]; //console.log(attr.nodeName,key)
68442
68443               if (attr.nodeName == key) {
68444                 return attr;
68445               }
68446             }
68447           },
68448           setNamedItem: function setNamedItem(attr) {
68449             var el = attr.ownerElement;
68450
68451             if (el && el != this._ownerElement) {
68452               throw new DOMException$2(INUSE_ATTRIBUTE_ERR);
68453             }
68454
68455             var oldAttr = this.getNamedItem(attr.nodeName);
68456
68457             _addNamedNode(this._ownerElement, this, attr, oldAttr);
68458
68459             return oldAttr;
68460           },
68461
68462           /* returns Node */
68463           setNamedItemNS: function setNamedItemNS(attr) {
68464             // raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR
68465             var el = attr.ownerElement,
68466                 oldAttr;
68467
68468             if (el && el != this._ownerElement) {
68469               throw new DOMException$2(INUSE_ATTRIBUTE_ERR);
68470             }
68471
68472             oldAttr = this.getNamedItemNS(attr.namespaceURI, attr.localName);
68473
68474             _addNamedNode(this._ownerElement, this, attr, oldAttr);
68475
68476             return oldAttr;
68477           },
68478
68479           /* returns Node */
68480           removeNamedItem: function removeNamedItem(key) {
68481             var attr = this.getNamedItem(key);
68482
68483             _removeNamedNode(this._ownerElement, this, attr);
68484
68485             return attr;
68486           },
68487           // raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR
68488           //for level2
68489           removeNamedItemNS: function removeNamedItemNS(namespaceURI, localName) {
68490             var attr = this.getNamedItemNS(namespaceURI, localName);
68491
68492             _removeNamedNode(this._ownerElement, this, attr);
68493
68494             return attr;
68495           },
68496           getNamedItemNS: function getNamedItemNS(namespaceURI, localName) {
68497             var i = this.length;
68498
68499             while (i--) {
68500               var node = this[i];
68501
68502               if (node.localName == localName && node.namespaceURI == namespaceURI) {
68503                 return node;
68504               }
68505             }
68506
68507             return null;
68508           }
68509         };
68510         /**
68511          * @see http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490
68512          */
68513
68514         function DOMImplementation(
68515         /* Object */
68516         features) {
68517           this._features = {};
68518
68519           if (features) {
68520             for (var feature in features) {
68521               this._features = features[feature];
68522             }
68523           }
68524         }
68525         DOMImplementation.prototype = {
68526           hasFeature: function hasFeature(
68527           /* string */
68528           feature,
68529           /* string */
68530           version) {
68531             var versions = this._features[feature.toLowerCase()];
68532
68533             if (versions && (!version || version in versions)) {
68534               return true;
68535             } else {
68536               return false;
68537             }
68538           },
68539           // Introduced in DOM Level 2:
68540           createDocument: function createDocument(namespaceURI, qualifiedName, doctype) {
68541             // raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR,WRONG_DOCUMENT_ERR
68542             var doc = new Document();
68543             doc.implementation = this;
68544             doc.childNodes = new NodeList();
68545             doc.doctype = doctype;
68546
68547             if (doctype) {
68548               doc.appendChild(doctype);
68549             }
68550
68551             if (qualifiedName) {
68552               var root = doc.createElementNS(namespaceURI, qualifiedName);
68553               doc.appendChild(root);
68554             }
68555
68556             return doc;
68557           },
68558           // Introduced in DOM Level 2:
68559           createDocumentType: function createDocumentType(qualifiedName, publicId, systemId) {
68560             // raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR
68561             var node = new DocumentType();
68562             node.name = qualifiedName;
68563             node.nodeName = qualifiedName;
68564             node.publicId = publicId;
68565             node.systemId = systemId; // Introduced in DOM Level 2:
68566             //readonly attribute DOMString        internalSubset;
68567             //TODO:..
68568             //  readonly attribute NamedNodeMap     entities;
68569             //  readonly attribute NamedNodeMap     notations;
68570
68571             return node;
68572           }
68573         };
68574         /**
68575          * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247
68576          */
68577
68578         function Node() {}
68579         Node.prototype = {
68580           firstChild: null,
68581           lastChild: null,
68582           previousSibling: null,
68583           nextSibling: null,
68584           attributes: null,
68585           parentNode: null,
68586           childNodes: null,
68587           ownerDocument: null,
68588           nodeValue: null,
68589           namespaceURI: null,
68590           prefix: null,
68591           localName: null,
68592           // Modified in DOM Level 2:
68593           insertBefore: function insertBefore(newChild, refChild) {
68594             //raises 
68595             return _insertBefore(this, newChild, refChild);
68596           },
68597           replaceChild: function replaceChild(newChild, oldChild) {
68598             //raises 
68599             this.insertBefore(newChild, oldChild);
68600
68601             if (oldChild) {
68602               this.removeChild(oldChild);
68603             }
68604           },
68605           removeChild: function removeChild(oldChild) {
68606             return _removeChild(this, oldChild);
68607           },
68608           appendChild: function appendChild(newChild) {
68609             return this.insertBefore(newChild, null);
68610           },
68611           hasChildNodes: function hasChildNodes() {
68612             return this.firstChild != null;
68613           },
68614           cloneNode: function cloneNode(deep) {
68615             return _cloneNode(this.ownerDocument || this, this, deep);
68616           },
68617           // Modified in DOM Level 2:
68618           normalize: function normalize() {
68619             var child = this.firstChild;
68620
68621             while (child) {
68622               var next = child.nextSibling;
68623
68624               if (next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE) {
68625                 this.removeChild(next);
68626                 child.appendData(next.data);
68627               } else {
68628                 child.normalize();
68629                 child = next;
68630               }
68631             }
68632           },
68633           // Introduced in DOM Level 2:
68634           isSupported: function isSupported(feature, version) {
68635             return this.ownerDocument.implementation.hasFeature(feature, version);
68636           },
68637           // Introduced in DOM Level 2:
68638           hasAttributes: function hasAttributes() {
68639             return this.attributes.length > 0;
68640           },
68641           lookupPrefix: function lookupPrefix(namespaceURI) {
68642             var el = this;
68643
68644             while (el) {
68645               var map = el._nsMap; //console.dir(map)
68646
68647               if (map) {
68648                 for (var n in map) {
68649                   if (map[n] == namespaceURI) {
68650                     return n;
68651                   }
68652                 }
68653               }
68654
68655               el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode;
68656             }
68657
68658             return null;
68659           },
68660           // Introduced in DOM Level 3:
68661           lookupNamespaceURI: function lookupNamespaceURI(prefix) {
68662             var el = this;
68663
68664             while (el) {
68665               var map = el._nsMap; //console.dir(map)
68666
68667               if (map) {
68668                 if (prefix in map) {
68669                   return map[prefix];
68670                 }
68671               }
68672
68673               el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode;
68674             }
68675
68676             return null;
68677           },
68678           // Introduced in DOM Level 3:
68679           isDefaultNamespace: function isDefaultNamespace(namespaceURI) {
68680             var prefix = this.lookupPrefix(namespaceURI);
68681             return prefix == null;
68682           }
68683         };
68684
68685         function _xmlEncoder(c) {
68686           return c == '<' && '&lt;' || c == '>' && '&gt;' || c == '&' && '&amp;' || c == '"' && '&quot;' || '&#' + c.charCodeAt() + ';';
68687         }
68688
68689         copy$1(NodeType, Node);
68690         copy$1(NodeType, Node.prototype);
68691         /**
68692          * @param callback return true for continue,false for break
68693          * @return boolean true: break visit;
68694          */
68695
68696         function _visitNode(node, callback) {
68697           if (callback(node)) {
68698             return true;
68699           }
68700
68701           if (node = node.firstChild) {
68702             do {
68703               if (_visitNode(node, callback)) {
68704                 return true;
68705               }
68706             } while (node = node.nextSibling);
68707           }
68708         }
68709
68710         function Document() {}
68711
68712         function _onAddAttribute(doc, el, newAttr) {
68713           doc && doc._inc++;
68714           var ns = newAttr.namespaceURI;
68715
68716           if (ns == 'http://www.w3.org/2000/xmlns/') {
68717             //update namespace
68718             el._nsMap[newAttr.prefix ? newAttr.localName : ''] = newAttr.value;
68719           }
68720         }
68721
68722         function _onRemoveAttribute(doc, el, newAttr, remove) {
68723           doc && doc._inc++;
68724           var ns = newAttr.namespaceURI;
68725
68726           if (ns == 'http://www.w3.org/2000/xmlns/') {
68727             //update namespace
68728             delete el._nsMap[newAttr.prefix ? newAttr.localName : ''];
68729           }
68730         }
68731
68732         function _onUpdateChild(doc, el, newChild) {
68733           if (doc && doc._inc) {
68734             doc._inc++; //update childNodes
68735
68736             var cs = el.childNodes;
68737
68738             if (newChild) {
68739               cs[cs.length++] = newChild;
68740             } else {
68741               //console.log(1)
68742               var child = el.firstChild;
68743               var i = 0;
68744
68745               while (child) {
68746                 cs[i++] = child;
68747                 child = child.nextSibling;
68748               }
68749
68750               cs.length = i;
68751             }
68752           }
68753         }
68754         /**
68755          * attributes;
68756          * children;
68757          * 
68758          * writeable properties:
68759          * nodeValue,Attr:value,CharacterData:data
68760          * prefix
68761          */
68762
68763
68764         function _removeChild(parentNode, child) {
68765           var previous = child.previousSibling;
68766           var next = child.nextSibling;
68767
68768           if (previous) {
68769             previous.nextSibling = next;
68770           } else {
68771             parentNode.firstChild = next;
68772           }
68773
68774           if (next) {
68775             next.previousSibling = previous;
68776           } else {
68777             parentNode.lastChild = previous;
68778           }
68779
68780           _onUpdateChild(parentNode.ownerDocument, parentNode);
68781
68782           return child;
68783         }
68784         /**
68785          * preformance key(refChild == null)
68786          */
68787
68788
68789         function _insertBefore(parentNode, newChild, nextChild) {
68790           var cp = newChild.parentNode;
68791
68792           if (cp) {
68793             cp.removeChild(newChild); //remove and update
68794           }
68795
68796           if (newChild.nodeType === DOCUMENT_FRAGMENT_NODE) {
68797             var newFirst = newChild.firstChild;
68798
68799             if (newFirst == null) {
68800               return newChild;
68801             }
68802
68803             var newLast = newChild.lastChild;
68804           } else {
68805             newFirst = newLast = newChild;
68806           }
68807
68808           var pre = nextChild ? nextChild.previousSibling : parentNode.lastChild;
68809           newFirst.previousSibling = pre;
68810           newLast.nextSibling = nextChild;
68811
68812           if (pre) {
68813             pre.nextSibling = newFirst;
68814           } else {
68815             parentNode.firstChild = newFirst;
68816           }
68817
68818           if (nextChild == null) {
68819             parentNode.lastChild = newLast;
68820           } else {
68821             nextChild.previousSibling = newLast;
68822           }
68823
68824           do {
68825             newFirst.parentNode = parentNode;
68826           } while (newFirst !== newLast && (newFirst = newFirst.nextSibling));
68827
68828           _onUpdateChild(parentNode.ownerDocument || parentNode, parentNode); //console.log(parentNode.lastChild.nextSibling == null)
68829
68830
68831           if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
68832             newChild.firstChild = newChild.lastChild = null;
68833           }
68834
68835           return newChild;
68836         }
68837
68838         function _appendSingleChild(parentNode, newChild) {
68839           var cp = newChild.parentNode;
68840
68841           if (cp) {
68842             var pre = parentNode.lastChild;
68843             cp.removeChild(newChild); //remove and update
68844
68845             var pre = parentNode.lastChild;
68846           }
68847
68848           var pre = parentNode.lastChild;
68849           newChild.parentNode = parentNode;
68850           newChild.previousSibling = pre;
68851           newChild.nextSibling = null;
68852
68853           if (pre) {
68854             pre.nextSibling = newChild;
68855           } else {
68856             parentNode.firstChild = newChild;
68857           }
68858
68859           parentNode.lastChild = newChild;
68860
68861           _onUpdateChild(parentNode.ownerDocument, parentNode, newChild);
68862
68863           return newChild; //console.log("__aa",parentNode.lastChild.nextSibling == null)
68864         }
68865
68866         Document.prototype = {
68867           //implementation : null,
68868           nodeName: '#document',
68869           nodeType: DOCUMENT_NODE,
68870           doctype: null,
68871           documentElement: null,
68872           _inc: 1,
68873           insertBefore: function insertBefore(newChild, refChild) {
68874             //raises 
68875             if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
68876               var child = newChild.firstChild;
68877
68878               while (child) {
68879                 var next = child.nextSibling;
68880                 this.insertBefore(child, refChild);
68881                 child = next;
68882               }
68883
68884               return newChild;
68885             }
68886
68887             if (this.documentElement == null && newChild.nodeType == ELEMENT_NODE) {
68888               this.documentElement = newChild;
68889             }
68890
68891             return _insertBefore(this, newChild, refChild), newChild.ownerDocument = this, newChild;
68892           },
68893           removeChild: function removeChild(oldChild) {
68894             if (this.documentElement == oldChild) {
68895               this.documentElement = null;
68896             }
68897
68898             return _removeChild(this, oldChild);
68899           },
68900           // Introduced in DOM Level 2:
68901           importNode: function importNode(importedNode, deep) {
68902             return _importNode(this, importedNode, deep);
68903           },
68904           // Introduced in DOM Level 2:
68905           getElementById: function getElementById(id) {
68906             var rtv = null;
68907
68908             _visitNode(this.documentElement, function (node) {
68909               if (node.nodeType == ELEMENT_NODE) {
68910                 if (node.getAttribute('id') == id) {
68911                   rtv = node;
68912                   return true;
68913                 }
68914               }
68915             });
68916
68917             return rtv;
68918           },
68919           //document factory method:
68920           createElement: function createElement(tagName) {
68921             var node = new Element();
68922             node.ownerDocument = this;
68923             node.nodeName = tagName;
68924             node.tagName = tagName;
68925             node.childNodes = new NodeList();
68926             var attrs = node.attributes = new NamedNodeMap();
68927             attrs._ownerElement = node;
68928             return node;
68929           },
68930           createDocumentFragment: function createDocumentFragment() {
68931             var node = new DocumentFragment();
68932             node.ownerDocument = this;
68933             node.childNodes = new NodeList();
68934             return node;
68935           },
68936           createTextNode: function createTextNode(data) {
68937             var node = new Text();
68938             node.ownerDocument = this;
68939             node.appendData(data);
68940             return node;
68941           },
68942           createComment: function createComment(data) {
68943             var node = new Comment();
68944             node.ownerDocument = this;
68945             node.appendData(data);
68946             return node;
68947           },
68948           createCDATASection: function createCDATASection(data) {
68949             var node = new CDATASection();
68950             node.ownerDocument = this;
68951             node.appendData(data);
68952             return node;
68953           },
68954           createProcessingInstruction: function createProcessingInstruction(target, data) {
68955             var node = new ProcessingInstruction();
68956             node.ownerDocument = this;
68957             node.tagName = node.target = target;
68958             node.nodeValue = node.data = data;
68959             return node;
68960           },
68961           createAttribute: function createAttribute(name) {
68962             var node = new Attr();
68963             node.ownerDocument = this;
68964             node.name = name;
68965             node.nodeName = name;
68966             node.localName = name;
68967             node.specified = true;
68968             return node;
68969           },
68970           createEntityReference: function createEntityReference(name) {
68971             var node = new EntityReference();
68972             node.ownerDocument = this;
68973             node.nodeName = name;
68974             return node;
68975           },
68976           // Introduced in DOM Level 2:
68977           createElementNS: function createElementNS(namespaceURI, qualifiedName) {
68978             var node = new Element();
68979             var pl = qualifiedName.split(':');
68980             var attrs = node.attributes = new NamedNodeMap();
68981             node.childNodes = new NodeList();
68982             node.ownerDocument = this;
68983             node.nodeName = qualifiedName;
68984             node.tagName = qualifiedName;
68985             node.namespaceURI = namespaceURI;
68986
68987             if (pl.length == 2) {
68988               node.prefix = pl[0];
68989               node.localName = pl[1];
68990             } else {
68991               //el.prefix = null;
68992               node.localName = qualifiedName;
68993             }
68994
68995             attrs._ownerElement = node;
68996             return node;
68997           },
68998           // Introduced in DOM Level 2:
68999           createAttributeNS: function createAttributeNS(namespaceURI, qualifiedName) {
69000             var node = new Attr();
69001             var pl = qualifiedName.split(':');
69002             node.ownerDocument = this;
69003             node.nodeName = qualifiedName;
69004             node.name = qualifiedName;
69005             node.namespaceURI = namespaceURI;
69006             node.specified = true;
69007
69008             if (pl.length == 2) {
69009               node.prefix = pl[0];
69010               node.localName = pl[1];
69011             } else {
69012               //el.prefix = null;
69013               node.localName = qualifiedName;
69014             }
69015
69016             return node;
69017           }
69018         };
69019
69020         _extends(Document, Node);
69021
69022         function Element() {
69023           this._nsMap = {};
69024         }
69025         Element.prototype = {
69026           nodeType: ELEMENT_NODE,
69027           hasAttribute: function hasAttribute(name) {
69028             return this.getAttributeNode(name) != null;
69029           },
69030           getAttribute: function getAttribute(name) {
69031             var attr = this.getAttributeNode(name);
69032             return attr && attr.value || '';
69033           },
69034           getAttributeNode: function getAttributeNode(name) {
69035             return this.attributes.getNamedItem(name);
69036           },
69037           setAttribute: function setAttribute(name, value) {
69038             var attr = this.ownerDocument.createAttribute(name);
69039             attr.value = attr.nodeValue = "" + value;
69040             this.setAttributeNode(attr);
69041           },
69042           removeAttribute: function removeAttribute(name) {
69043             var attr = this.getAttributeNode(name);
69044             attr && this.removeAttributeNode(attr);
69045           },
69046           //four real opeartion method
69047           appendChild: function appendChild(newChild) {
69048             if (newChild.nodeType === DOCUMENT_FRAGMENT_NODE) {
69049               return this.insertBefore(newChild, null);
69050             } else {
69051               return _appendSingleChild(this, newChild);
69052             }
69053           },
69054           setAttributeNode: function setAttributeNode(newAttr) {
69055             return this.attributes.setNamedItem(newAttr);
69056           },
69057           setAttributeNodeNS: function setAttributeNodeNS(newAttr) {
69058             return this.attributes.setNamedItemNS(newAttr);
69059           },
69060           removeAttributeNode: function removeAttributeNode(oldAttr) {
69061             //console.log(this == oldAttr.ownerElement)
69062             return this.attributes.removeNamedItem(oldAttr.nodeName);
69063           },
69064           //get real attribute name,and remove it by removeAttributeNode
69065           removeAttributeNS: function removeAttributeNS(namespaceURI, localName) {
69066             var old = this.getAttributeNodeNS(namespaceURI, localName);
69067             old && this.removeAttributeNode(old);
69068           },
69069           hasAttributeNS: function hasAttributeNS(namespaceURI, localName) {
69070             return this.getAttributeNodeNS(namespaceURI, localName) != null;
69071           },
69072           getAttributeNS: function getAttributeNS(namespaceURI, localName) {
69073             var attr = this.getAttributeNodeNS(namespaceURI, localName);
69074             return attr && attr.value || '';
69075           },
69076           setAttributeNS: function setAttributeNS(namespaceURI, qualifiedName, value) {
69077             var attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);
69078             attr.value = attr.nodeValue = "" + value;
69079             this.setAttributeNode(attr);
69080           },
69081           getAttributeNodeNS: function getAttributeNodeNS(namespaceURI, localName) {
69082             return this.attributes.getNamedItemNS(namespaceURI, localName);
69083           },
69084           getElementsByTagName: function getElementsByTagName(tagName) {
69085             return new LiveNodeList(this, function (base) {
69086               var ls = [];
69087
69088               _visitNode(base, function (node) {
69089                 if (node !== base && node.nodeType == ELEMENT_NODE && (tagName === '*' || node.tagName == tagName)) {
69090                   ls.push(node);
69091                 }
69092               });
69093
69094               return ls;
69095             });
69096           },
69097           getElementsByTagNameNS: function getElementsByTagNameNS(namespaceURI, localName) {
69098             return new LiveNodeList(this, function (base) {
69099               var ls = [];
69100
69101               _visitNode(base, function (node) {
69102                 if (node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName)) {
69103                   ls.push(node);
69104                 }
69105               });
69106
69107               return ls;
69108             });
69109           }
69110         };
69111         Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;
69112         Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;
69113
69114         _extends(Element, Node);
69115
69116         function Attr() {}
69117         Attr.prototype.nodeType = ATTRIBUTE_NODE;
69118
69119         _extends(Attr, Node);
69120
69121         function CharacterData() {}
69122         CharacterData.prototype = {
69123           data: '',
69124           substringData: function substringData(offset, count) {
69125             return this.data.substring(offset, offset + count);
69126           },
69127           appendData: function appendData(text) {
69128             text = this.data + text;
69129             this.nodeValue = this.data = text;
69130             this.length = text.length;
69131           },
69132           insertData: function insertData(offset, text) {
69133             this.replaceData(offset, 0, text);
69134           },
69135           appendChild: function appendChild(newChild) {
69136             throw new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR]);
69137           },
69138           deleteData: function deleteData(offset, count) {
69139             this.replaceData(offset, count, "");
69140           },
69141           replaceData: function replaceData(offset, count, text) {
69142             var start = this.data.substring(0, offset);
69143             var end = this.data.substring(offset + count);
69144             text = start + text + end;
69145             this.nodeValue = this.data = text;
69146             this.length = text.length;
69147           }
69148         };
69149
69150         _extends(CharacterData, Node);
69151
69152         function Text() {}
69153         Text.prototype = {
69154           nodeName: "#text",
69155           nodeType: TEXT_NODE,
69156           splitText: function splitText(offset) {
69157             var text = this.data;
69158             var newText = text.substring(offset);
69159             text = text.substring(0, offset);
69160             this.data = this.nodeValue = text;
69161             this.length = text.length;
69162             var newNode = this.ownerDocument.createTextNode(newText);
69163
69164             if (this.parentNode) {
69165               this.parentNode.insertBefore(newNode, this.nextSibling);
69166             }
69167
69168             return newNode;
69169           }
69170         };
69171
69172         _extends(Text, CharacterData);
69173
69174         function Comment() {}
69175         Comment.prototype = {
69176           nodeName: "#comment",
69177           nodeType: COMMENT_NODE
69178         };
69179
69180         _extends(Comment, CharacterData);
69181
69182         function CDATASection() {}
69183         CDATASection.prototype = {
69184           nodeName: "#cdata-section",
69185           nodeType: CDATA_SECTION_NODE
69186         };
69187
69188         _extends(CDATASection, CharacterData);
69189
69190         function DocumentType() {}
69191         DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;
69192
69193         _extends(DocumentType, Node);
69194
69195         function Notation() {}
69196         Notation.prototype.nodeType = NOTATION_NODE;
69197
69198         _extends(Notation, Node);
69199
69200         function Entity() {}
69201         Entity.prototype.nodeType = ENTITY_NODE;
69202
69203         _extends(Entity, Node);
69204
69205         function EntityReference() {}
69206         EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;
69207
69208         _extends(EntityReference, Node);
69209
69210         function DocumentFragment() {}
69211         DocumentFragment.prototype.nodeName = "#document-fragment";
69212         DocumentFragment.prototype.nodeType = DOCUMENT_FRAGMENT_NODE;
69213
69214         _extends(DocumentFragment, Node);
69215
69216         function ProcessingInstruction() {}
69217
69218         ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;
69219
69220         _extends(ProcessingInstruction, Node);
69221
69222         function XMLSerializer$1() {}
69223
69224         XMLSerializer$1.prototype.serializeToString = function (node, isHtml, nodeFilter) {
69225           return nodeSerializeToString.call(node, isHtml, nodeFilter);
69226         };
69227
69228         Node.prototype.toString = nodeSerializeToString;
69229
69230         function nodeSerializeToString(isHtml, nodeFilter) {
69231           var buf = [];
69232           var refNode = this.nodeType == 9 ? this.documentElement : this;
69233           var prefix = refNode.prefix;
69234           var uri = refNode.namespaceURI;
69235
69236           if (uri && prefix == null) {
69237             //console.log(prefix)
69238             var prefix = refNode.lookupPrefix(uri);
69239
69240             if (prefix == null) {
69241               //isHTML = true;
69242               var visibleNamespaces = [{
69243                 namespace: uri,
69244                 prefix: null
69245               } //{namespace:uri,prefix:''}
69246               ];
69247             }
69248           }
69249
69250           serializeToString(this, buf, isHtml, nodeFilter, visibleNamespaces); //console.log('###',this.nodeType,uri,prefix,buf.join(''))
69251
69252           return buf.join('');
69253         }
69254
69255         function needNamespaceDefine(node, isHTML, visibleNamespaces) {
69256           var prefix = node.prefix || '';
69257           var uri = node.namespaceURI;
69258
69259           if (!prefix && !uri) {
69260             return false;
69261           }
69262
69263           if (prefix === "xml" && uri === "http://www.w3.org/XML/1998/namespace" || uri == 'http://www.w3.org/2000/xmlns/') {
69264             return false;
69265           }
69266
69267           var i = visibleNamespaces.length; //console.log('@@@@',node.tagName,prefix,uri,visibleNamespaces)
69268
69269           while (i--) {
69270             var ns = visibleNamespaces[i]; // get namespace prefix
69271             //console.log(node.nodeType,node.tagName,ns.prefix,prefix)
69272
69273             if (ns.prefix == prefix) {
69274               return ns.namespace != uri;
69275             }
69276           } //console.log(isHTML,uri,prefix=='')
69277           //if(isHTML && prefix ==null && uri == 'http://www.w3.org/1999/xhtml'){
69278           //    return false;
69279           //}
69280           //node.flag = '11111'
69281           //console.error(3,true,node.flag,node.prefix,node.namespaceURI)
69282
69283
69284           return true;
69285         }
69286
69287         function serializeToString(node, buf, isHTML, nodeFilter, visibleNamespaces) {
69288           if (nodeFilter) {
69289             node = nodeFilter(node);
69290
69291             if (node) {
69292               if (typeof node == 'string') {
69293                 buf.push(node);
69294                 return;
69295               }
69296             } else {
69297               return;
69298             } //buf.sort.apply(attrs, attributeSorter);
69299
69300           }
69301
69302           switch (node.nodeType) {
69303             case ELEMENT_NODE:
69304               if (!visibleNamespaces) visibleNamespaces = [];
69305               var startVisibleNamespaces = visibleNamespaces.length;
69306               var attrs = node.attributes;
69307               var len = attrs.length;
69308               var child = node.firstChild;
69309               var nodeName = node.tagName;
69310               isHTML = htmlns === node.namespaceURI || isHTML;
69311               buf.push('<', nodeName);
69312
69313               for (var i = 0; i < len; i++) {
69314                 // add namespaces for attributes
69315                 var attr = attrs.item(i);
69316
69317                 if (attr.prefix == 'xmlns') {
69318                   visibleNamespaces.push({
69319                     prefix: attr.localName,
69320                     namespace: attr.value
69321                   });
69322                 } else if (attr.nodeName == 'xmlns') {
69323                   visibleNamespaces.push({
69324                     prefix: '',
69325                     namespace: attr.value
69326                   });
69327                 }
69328               }
69329
69330               for (var i = 0; i < len; i++) {
69331                 var attr = attrs.item(i);
69332
69333                 if (needNamespaceDefine(attr, isHTML, visibleNamespaces)) {
69334                   var prefix = attr.prefix || '';
69335                   var uri = attr.namespaceURI;
69336                   var ns = prefix ? ' xmlns:' + prefix : " xmlns";
69337                   buf.push(ns, '="', uri, '"');
69338                   visibleNamespaces.push({
69339                     prefix: prefix,
69340                     namespace: uri
69341                   });
69342                 }
69343
69344                 serializeToString(attr, buf, isHTML, nodeFilter, visibleNamespaces);
69345               } // add namespace for current node               
69346
69347
69348               if (needNamespaceDefine(node, isHTML, visibleNamespaces)) {
69349                 var prefix = node.prefix || '';
69350                 var uri = node.namespaceURI;
69351                 var ns = prefix ? ' xmlns:' + prefix : " xmlns";
69352                 buf.push(ns, '="', uri, '"');
69353                 visibleNamespaces.push({
69354                   prefix: prefix,
69355                   namespace: uri
69356                 });
69357               }
69358
69359               if (child || isHTML && !/^(?:meta|link|img|br|hr|input)$/i.test(nodeName)) {
69360                 buf.push('>'); //if is cdata child node
69361
69362                 if (isHTML && /^script$/i.test(nodeName)) {
69363                   while (child) {
69364                     if (child.data) {
69365                       buf.push(child.data);
69366                     } else {
69367                       serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces);
69368                     }
69369
69370                     child = child.nextSibling;
69371                   }
69372                 } else {
69373                   while (child) {
69374                     serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces);
69375                     child = child.nextSibling;
69376                   }
69377                 }
69378
69379                 buf.push('</', nodeName, '>');
69380               } else {
69381                 buf.push('/>');
69382               } // remove added visible namespaces
69383               //visibleNamespaces.length = startVisibleNamespaces;
69384
69385
69386               return;
69387
69388             case DOCUMENT_NODE:
69389             case DOCUMENT_FRAGMENT_NODE:
69390               var child = node.firstChild;
69391
69392               while (child) {
69393                 serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces);
69394                 child = child.nextSibling;
69395               }
69396
69397               return;
69398
69399             case ATTRIBUTE_NODE:
69400               return buf.push(' ', node.name, '="', node.value.replace(/[<&"]/g, _xmlEncoder), '"');
69401
69402             case TEXT_NODE:
69403               return buf.push(node.data.replace(/[<&]/g, _xmlEncoder));
69404
69405             case CDATA_SECTION_NODE:
69406               return buf.push('<![CDATA[', node.data, ']]>');
69407
69408             case COMMENT_NODE:
69409               return buf.push("<!--", node.data, "-->");
69410
69411             case DOCUMENT_TYPE_NODE:
69412               var pubid = node.publicId;
69413               var sysid = node.systemId;
69414               buf.push('<!DOCTYPE ', node.name);
69415
69416               if (pubid) {
69417                 buf.push(' PUBLIC "', pubid);
69418
69419                 if (sysid && sysid != '.') {
69420                   buf.push('" "', sysid);
69421                 }
69422
69423                 buf.push('">');
69424               } else if (sysid && sysid != '.') {
69425                 buf.push(' SYSTEM "', sysid, '">');
69426               } else {
69427                 var sub = node.internalSubset;
69428
69429                 if (sub) {
69430                   buf.push(" [", sub, "]");
69431                 }
69432
69433                 buf.push(">");
69434               }
69435
69436               return;
69437
69438             case PROCESSING_INSTRUCTION_NODE:
69439               return buf.push("<?", node.target, " ", node.data, "?>");
69440
69441             case ENTITY_REFERENCE_NODE:
69442               return buf.push('&', node.nodeName, ';');
69443             //case ENTITY_NODE:
69444             //case NOTATION_NODE:
69445
69446             default:
69447               buf.push('??', node.nodeName);
69448           }
69449         }
69450
69451         function _importNode(doc, node, deep) {
69452           var node2;
69453
69454           switch (node.nodeType) {
69455             case ELEMENT_NODE:
69456               node2 = node.cloneNode(false);
69457               node2.ownerDocument = doc;
69458             //var attrs = node2.attributes;
69459             //var len = attrs.length;
69460             //for(var i=0;i<len;i++){
69461             //node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep));
69462             //}
69463
69464             case DOCUMENT_FRAGMENT_NODE:
69465               break;
69466
69467             case ATTRIBUTE_NODE:
69468               deep = true;
69469               break;
69470             //case ENTITY_REFERENCE_NODE:
69471             //case PROCESSING_INSTRUCTION_NODE:
69472             ////case TEXT_NODE:
69473             //case CDATA_SECTION_NODE:
69474             //case COMMENT_NODE:
69475             //  deep = false;
69476             //  break;
69477             //case DOCUMENT_NODE:
69478             //case DOCUMENT_TYPE_NODE:
69479             //cannot be imported.
69480             //case ENTITY_NODE:
69481             //case NOTATION_NODE:
69482             //can not hit in level3
69483             //default:throw e;
69484           }
69485
69486           if (!node2) {
69487             node2 = node.cloneNode(false); //false
69488           }
69489
69490           node2.ownerDocument = doc;
69491           node2.parentNode = null;
69492
69493           if (deep) {
69494             var child = node.firstChild;
69495
69496             while (child) {
69497               node2.appendChild(_importNode(doc, child, deep));
69498               child = child.nextSibling;
69499             }
69500           }
69501
69502           return node2;
69503         } //
69504         //var _relationMap = {firstChild:1,lastChild:1,previousSibling:1,nextSibling:1,
69505         //                                      attributes:1,childNodes:1,parentNode:1,documentElement:1,doctype,};
69506
69507
69508         function _cloneNode(doc, node, deep) {
69509           var node2 = new node.constructor();
69510
69511           for (var n in node) {
69512             var v = node[n];
69513
69514             if (_typeof(v) != 'object') {
69515               if (v != node2[n]) {
69516                 node2[n] = v;
69517               }
69518             }
69519           }
69520
69521           if (node.childNodes) {
69522             node2.childNodes = new NodeList();
69523           }
69524
69525           node2.ownerDocument = doc;
69526
69527           switch (node2.nodeType) {
69528             case ELEMENT_NODE:
69529               var attrs = node.attributes;
69530               var attrs2 = node2.attributes = new NamedNodeMap();
69531               var len = attrs.length;
69532               attrs2._ownerElement = node2;
69533
69534               for (var i = 0; i < len; i++) {
69535                 node2.setAttributeNode(_cloneNode(doc, attrs.item(i), true));
69536               }
69537
69538               break;
69539
69540             case ATTRIBUTE_NODE:
69541               deep = true;
69542           }
69543
69544           if (deep) {
69545             var child = node.firstChild;
69546
69547             while (child) {
69548               node2.appendChild(_cloneNode(doc, child, deep));
69549               child = child.nextSibling;
69550             }
69551           }
69552
69553           return node2;
69554         }
69555
69556         function __set__(object, key, value) {
69557           object[key] = value;
69558         } //do dynamic
69559
69560
69561         try {
69562           if (Object.defineProperty) {
69563             var getTextContent = function getTextContent(node) {
69564               switch (node.nodeType) {
69565                 case ELEMENT_NODE:
69566                 case DOCUMENT_FRAGMENT_NODE:
69567                   var buf = [];
69568                   node = node.firstChild;
69569
69570                   while (node) {
69571                     if (node.nodeType !== 7 && node.nodeType !== 8) {
69572                       buf.push(getTextContent(node));
69573                     }
69574
69575                     node = node.nextSibling;
69576                   }
69577
69578                   return buf.join('');
69579
69580                 default:
69581                   return node.nodeValue;
69582               }
69583             };
69584
69585             Object.defineProperty(LiveNodeList.prototype, 'length', {
69586               get: function get() {
69587                 _updateLiveList(this);
69588
69589                 return this.$$length;
69590               }
69591             });
69592             Object.defineProperty(Node.prototype, 'textContent', {
69593               get: function get() {
69594                 return getTextContent(this);
69595               },
69596               set: function set(data) {
69597                 switch (this.nodeType) {
69598                   case ELEMENT_NODE:
69599                   case DOCUMENT_FRAGMENT_NODE:
69600                     while (this.firstChild) {
69601                       this.removeChild(this.firstChild);
69602                     }
69603
69604                     if (data || String(data)) {
69605                       this.appendChild(this.ownerDocument.createTextNode(data));
69606                     }
69607
69608                     break;
69609
69610                   default:
69611                     //TODO:
69612                     this.data = data;
69613                     this.value = data;
69614                     this.nodeValue = data;
69615                 }
69616               }
69617             });
69618
69619             __set__ = function __set__(object, key, value) {
69620               //console.log(value)
69621               object['$$' + key] = value;
69622             };
69623           }
69624         } catch (e) {//ie8
69625         } //if(typeof require == 'function'){
69626
69627
69628         var DOMImplementation_1 = DOMImplementation;
69629         var XMLSerializer_1 = XMLSerializer$1; //}
69630
69631         var dom = {
69632           DOMImplementation: DOMImplementation_1,
69633           XMLSerializer: XMLSerializer_1
69634         };
69635
69636         var domParser = createCommonjsModule(function (module, exports) {
69637           function DOMParser(options) {
69638             this.options = options || {
69639               locator: {}
69640             };
69641           }
69642
69643           DOMParser.prototype.parseFromString = function (source, mimeType) {
69644             var options = this.options;
69645             var sax = new XMLReader();
69646             var domBuilder = options.domBuilder || new DOMHandler(); //contentHandler and LexicalHandler
69647
69648             var errorHandler = options.errorHandler;
69649             var locator = options.locator;
69650             var defaultNSMap = options.xmlns || {};
69651             var entityMap = {
69652               'lt': '<',
69653               'gt': '>',
69654               'amp': '&',
69655               'quot': '"',
69656               'apos': "'"
69657             };
69658
69659             if (locator) {
69660               domBuilder.setDocumentLocator(locator);
69661             }
69662
69663             sax.errorHandler = buildErrorHandler(errorHandler, domBuilder, locator);
69664             sax.domBuilder = options.domBuilder || domBuilder;
69665
69666             if (/\/x?html?$/.test(mimeType)) {
69667               entityMap.nbsp = '\xa0';
69668               entityMap.copy = '\xa9';
69669               defaultNSMap[''] = 'http://www.w3.org/1999/xhtml';
69670             }
69671
69672             defaultNSMap.xml = defaultNSMap.xml || 'http://www.w3.org/XML/1998/namespace';
69673
69674             if (source) {
69675               sax.parse(source, defaultNSMap, entityMap);
69676             } else {
69677               sax.errorHandler.error("invalid doc source");
69678             }
69679
69680             return domBuilder.doc;
69681           };
69682
69683           function buildErrorHandler(errorImpl, domBuilder, locator) {
69684             if (!errorImpl) {
69685               if (domBuilder instanceof DOMHandler) {
69686                 return domBuilder;
69687               }
69688
69689               errorImpl = domBuilder;
69690             }
69691
69692             var errorHandler = {};
69693             var isCallback = errorImpl instanceof Function;
69694             locator = locator || {};
69695
69696             function build(key) {
69697               var fn = errorImpl[key];
69698
69699               if (!fn && isCallback) {
69700                 fn = errorImpl.length == 2 ? function (msg) {
69701                   errorImpl(key, msg);
69702                 } : errorImpl;
69703               }
69704
69705               errorHandler[key] = fn && function (msg) {
69706                 fn('[xmldom ' + key + ']\t' + msg + _locator(locator));
69707               } || function () {};
69708             }
69709
69710             build('warning');
69711             build('error');
69712             build('fatalError');
69713             return errorHandler;
69714           } //console.log('#\n\n\n\n\n\n\n####')
69715
69716           /**
69717            * +ContentHandler+ErrorHandler
69718            * +LexicalHandler+EntityResolver2
69719            * -DeclHandler-DTDHandler 
69720            * 
69721            * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler
69722            * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2
69723            * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
69724            */
69725
69726
69727           function DOMHandler() {
69728             this.cdata = false;
69729           }
69730
69731           function position(locator, node) {
69732             node.lineNumber = locator.lineNumber;
69733             node.columnNumber = locator.columnNumber;
69734           }
69735           /**
69736            * @see org.xml.sax.ContentHandler#startDocument
69737            * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
69738            */
69739
69740
69741           DOMHandler.prototype = {
69742             startDocument: function startDocument() {
69743               this.doc = new DOMImplementation().createDocument(null, null, null);
69744
69745               if (this.locator) {
69746                 this.doc.documentURI = this.locator.systemId;
69747               }
69748             },
69749             startElement: function startElement(namespaceURI, localName, qName, attrs) {
69750               var doc = this.doc;
69751               var el = doc.createElementNS(namespaceURI, qName || localName);
69752               var len = attrs.length;
69753               appendElement(this, el);
69754               this.currentElement = el;
69755               this.locator && position(this.locator, el);
69756
69757               for (var i = 0; i < len; i++) {
69758                 var namespaceURI = attrs.getURI(i);
69759                 var value = attrs.getValue(i);
69760                 var qName = attrs.getQName(i);
69761                 var attr = doc.createAttributeNS(namespaceURI, qName);
69762                 this.locator && position(attrs.getLocator(i), attr);
69763                 attr.value = attr.nodeValue = value;
69764                 el.setAttributeNode(attr);
69765               }
69766             },
69767             endElement: function endElement(namespaceURI, localName, qName) {
69768               var current = this.currentElement;
69769               var tagName = current.tagName;
69770               this.currentElement = current.parentNode;
69771             },
69772             startPrefixMapping: function startPrefixMapping(prefix, uri) {},
69773             endPrefixMapping: function endPrefixMapping(prefix) {},
69774             processingInstruction: function processingInstruction(target, data) {
69775               var ins = this.doc.createProcessingInstruction(target, data);
69776               this.locator && position(this.locator, ins);
69777               appendElement(this, ins);
69778             },
69779             ignorableWhitespace: function ignorableWhitespace(ch, start, length) {},
69780             characters: function characters(chars, start, length) {
69781               chars = _toString.apply(this, arguments); //console.log(chars)
69782
69783               if (chars) {
69784                 if (this.cdata) {
69785                   var charNode = this.doc.createCDATASection(chars);
69786                 } else {
69787                   var charNode = this.doc.createTextNode(chars);
69788                 }
69789
69790                 if (this.currentElement) {
69791                   this.currentElement.appendChild(charNode);
69792                 } else if (/^\s*$/.test(chars)) {
69793                   this.doc.appendChild(charNode); //process xml
69794                 }
69795
69796                 this.locator && position(this.locator, charNode);
69797               }
69798             },
69799             skippedEntity: function skippedEntity(name) {},
69800             endDocument: function endDocument() {
69801               this.doc.normalize();
69802             },
69803             setDocumentLocator: function setDocumentLocator(locator) {
69804               if (this.locator = locator) {
69805                 // && !('lineNumber' in locator)){
69806                 locator.lineNumber = 0;
69807               }
69808             },
69809             //LexicalHandler
69810             comment: function comment(chars, start, length) {
69811               chars = _toString.apply(this, arguments);
69812               var comm = this.doc.createComment(chars);
69813               this.locator && position(this.locator, comm);
69814               appendElement(this, comm);
69815             },
69816             startCDATA: function startCDATA() {
69817               //used in characters() methods
69818               this.cdata = true;
69819             },
69820             endCDATA: function endCDATA() {
69821               this.cdata = false;
69822             },
69823             startDTD: function startDTD(name, publicId, systemId) {
69824               var impl = this.doc.implementation;
69825
69826               if (impl && impl.createDocumentType) {
69827                 var dt = impl.createDocumentType(name, publicId, systemId);
69828                 this.locator && position(this.locator, dt);
69829                 appendElement(this, dt);
69830               }
69831             },
69832
69833             /**
69834              * @see org.xml.sax.ErrorHandler
69835              * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
69836              */
69837             warning: function warning(error) {
69838               console.warn('[xmldom warning]\t' + error, _locator(this.locator));
69839             },
69840             error: function error(_error) {
69841               console.error('[xmldom error]\t' + _error, _locator(this.locator));
69842             },
69843             fatalError: function fatalError(error) {
69844               console.error('[xmldom fatalError]\t' + error, _locator(this.locator));
69845               throw error;
69846             }
69847           };
69848
69849           function _locator(l) {
69850             if (l) {
69851               return '\n@' + (l.systemId || '') + '#[line:' + l.lineNumber + ',col:' + l.columnNumber + ']';
69852             }
69853           }
69854
69855           function _toString(chars, start, length) {
69856             if (typeof chars == 'string') {
69857               return chars.substr(start, length);
69858             } else {
69859               //java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
69860               if (chars.length >= start + length || start) {
69861                 return new java.lang.String(chars, start, length) + '';
69862               }
69863
69864               return chars;
69865             }
69866           }
69867           /*
69868            * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
69869            * used method of org.xml.sax.ext.LexicalHandler:
69870            *  #comment(chars, start, length)
69871            *  #startCDATA()
69872            *  #endCDATA()
69873            *  #startDTD(name, publicId, systemId)
69874            *
69875            *
69876            * IGNORED method of org.xml.sax.ext.LexicalHandler:
69877            *  #endDTD()
69878            *  #startEntity(name)
69879            *  #endEntity(name)
69880            *
69881            *
69882            * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
69883            * IGNORED method of org.xml.sax.ext.DeclHandler
69884            *    #attributeDecl(eName, aName, type, mode, value)
69885            *  #elementDecl(name, model)
69886            *  #externalEntityDecl(name, publicId, systemId)
69887            *  #internalEntityDecl(name, value)
69888            * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
69889            * IGNORED method of org.xml.sax.EntityResolver2
69890            *  #resolveEntity(String name,String publicId,String baseURI,String systemId)
69891            *  #resolveEntity(publicId, systemId)
69892            *  #getExternalSubset(name, baseURI)
69893            * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
69894            * IGNORED method of org.xml.sax.DTDHandler
69895            *  #notationDecl(name, publicId, systemId) {};
69896            *  #unparsedEntityDecl(name, publicId, systemId, notationName) {};
69897            */
69898
69899
69900           "endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g, function (key) {
69901             DOMHandler.prototype[key] = function () {
69902               return null;
69903             };
69904           });
69905           /* 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 */
69906
69907           function appendElement(hander, node) {
69908             if (!hander.currentElement) {
69909               hander.doc.appendChild(node);
69910             } else {
69911               hander.currentElement.appendChild(node);
69912             }
69913           } //appendChild and setAttributeNS are preformance key
69914           //if(typeof require == 'function'){
69915
69916
69917           var XMLReader = sax.XMLReader;
69918           var DOMImplementation = exports.DOMImplementation = dom.DOMImplementation;
69919           exports.XMLSerializer = dom.XMLSerializer;
69920           exports.DOMParser = DOMParser; //}
69921         });
69922
69923         var togeojson = createCommonjsModule(function (module, exports) {
69924           var toGeoJSON = function () {
69925
69926             var removeSpace = /\s*/g,
69927                 trimSpace = /^\s*|\s*$/g,
69928                 splitSpace = /\s+/; // generate a short, numeric hash of a string
69929
69930             function okhash(x) {
69931               if (!x || !x.length) return 0;
69932
69933               for (var i = 0, h = 0; i < x.length; i++) {
69934                 h = (h << 5) - h + x.charCodeAt(i) | 0;
69935               }
69936
69937               return h;
69938             } // all Y children of X
69939
69940
69941             function get(x, y) {
69942               return x.getElementsByTagName(y);
69943             }
69944
69945             function attr(x, y) {
69946               return x.getAttribute(y);
69947             }
69948
69949             function attrf(x, y) {
69950               return parseFloat(attr(x, y));
69951             } // one Y child of X, if any, otherwise null
69952
69953
69954             function get1(x, y) {
69955               var n = get(x, y);
69956               return n.length ? n[0] : null;
69957             } // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
69958
69959
69960             function norm(el) {
69961               if (el.normalize) {
69962                 el.normalize();
69963               }
69964
69965               return el;
69966             } // cast array x into numbers
69967
69968
69969             function numarray(x) {
69970               for (var j = 0, o = []; j < x.length; j++) {
69971                 o[j] = parseFloat(x[j]);
69972               }
69973
69974               return o;
69975             } // get the content of a text node, if any
69976
69977
69978             function nodeVal(x) {
69979               if (x) {
69980                 norm(x);
69981               }
69982
69983               return x && x.textContent || '';
69984             } // get the contents of multiple text nodes, if present
69985
69986
69987             function getMulti(x, ys) {
69988               var o = {},
69989                   n,
69990                   k;
69991
69992               for (k = 0; k < ys.length; k++) {
69993                 n = get1(x, ys[k]);
69994                 if (n) o[ys[k]] = nodeVal(n);
69995               }
69996
69997               return o;
69998             } // add properties of Y to X, overwriting if present in both
69999
70000
70001             function extend(x, y) {
70002               for (var k in y) {
70003                 x[k] = y[k];
70004               }
70005             } // get one coordinate from a coordinate array, if any
70006
70007
70008             function coord1(v) {
70009               return numarray(v.replace(removeSpace, '').split(','));
70010             } // get all coordinates from a coordinate array as [[],[]]
70011
70012
70013             function coord(v) {
70014               var coords = v.replace(trimSpace, '').split(splitSpace),
70015                   o = [];
70016
70017               for (var i = 0; i < coords.length; i++) {
70018                 o.push(coord1(coords[i]));
70019               }
70020
70021               return o;
70022             }
70023
70024             function coordPair(x) {
70025               var ll = [attrf(x, 'lon'), attrf(x, 'lat')],
70026                   ele = get1(x, 'ele'),
70027                   // handle namespaced attribute in browser
70028               heartRate = get1(x, 'gpxtpx:hr') || get1(x, 'hr'),
70029                   time = get1(x, 'time'),
70030                   e;
70031
70032               if (ele) {
70033                 e = parseFloat(nodeVal(ele));
70034
70035                 if (!isNaN(e)) {
70036                   ll.push(e);
70037                 }
70038               }
70039
70040               return {
70041                 coordinates: ll,
70042                 time: time ? nodeVal(time) : null,
70043                 heartRate: heartRate ? parseFloat(nodeVal(heartRate)) : null
70044               };
70045             } // create a new feature collection parent object
70046
70047
70048             function fc() {
70049               return {
70050                 type: 'FeatureCollection',
70051                 features: []
70052               };
70053             }
70054
70055             var serializer;
70056
70057             if (typeof XMLSerializer !== 'undefined') {
70058               /* istanbul ignore next */
70059               serializer = new XMLSerializer(); // only require xmldom in a node environment
70060             } else if ( (typeof process === "undefined" ? "undefined" : _typeof(process)) === 'object' && !process.browser) {
70061               serializer = new domParser.XMLSerializer();
70062             }
70063
70064             function xml2str(str) {
70065               // IE9 will create a new XMLSerializer but it'll crash immediately.
70066               // This line is ignored because we don't run coverage tests in IE9
70067
70068               /* istanbul ignore next */
70069               if (str.xml !== undefined) return str.xml;
70070               return serializer.serializeToString(str);
70071             }
70072
70073             var t = {
70074               kml: function kml(doc) {
70075                 var gj = fc(),
70076                     // styleindex keeps track of hashed styles in order to match features
70077                 styleIndex = {},
70078                     styleByHash = {},
70079                     // stylemapindex keeps track of style maps to expose in properties
70080                 styleMapIndex = {},
70081                     // atomic geospatial types supported by KML - MultiGeometry is
70082                 // handled separately
70083                 geotypes = ['Polygon', 'LineString', 'Point', 'Track', 'gx:Track'],
70084                     // all root placemarks in the file
70085                 placemarks = get(doc, 'Placemark'),
70086                     styles = get(doc, 'Style'),
70087                     styleMaps = get(doc, 'StyleMap');
70088
70089                 for (var k = 0; k < styles.length; k++) {
70090                   var hash = okhash(xml2str(styles[k])).toString(16);
70091                   styleIndex['#' + attr(styles[k], 'id')] = hash;
70092                   styleByHash[hash] = styles[k];
70093                 }
70094
70095                 for (var l = 0; l < styleMaps.length; l++) {
70096                   styleIndex['#' + attr(styleMaps[l], 'id')] = okhash(xml2str(styleMaps[l])).toString(16);
70097                   var pairs = get(styleMaps[l], 'Pair');
70098                   var pairsMap = {};
70099
70100                   for (var m = 0; m < pairs.length; m++) {
70101                     pairsMap[nodeVal(get1(pairs[m], 'key'))] = nodeVal(get1(pairs[m], 'styleUrl'));
70102                   }
70103
70104                   styleMapIndex['#' + attr(styleMaps[l], 'id')] = pairsMap;
70105                 }
70106
70107                 for (var j = 0; j < placemarks.length; j++) {
70108                   gj.features = gj.features.concat(getPlacemark(placemarks[j]));
70109                 }
70110
70111                 function kmlColor(v) {
70112                   var color, opacity;
70113                   v = v || '';
70114
70115                   if (v.substr(0, 1) === '#') {
70116                     v = v.substr(1);
70117                   }
70118
70119                   if (v.length === 6 || v.length === 3) {
70120                     color = v;
70121                   }
70122
70123                   if (v.length === 8) {
70124                     opacity = parseInt(v.substr(0, 2), 16) / 255;
70125                     color = '#' + v.substr(6, 2) + v.substr(4, 2) + v.substr(2, 2);
70126                   }
70127
70128                   return [color, isNaN(opacity) ? undefined : opacity];
70129                 }
70130
70131                 function gxCoord(v) {
70132                   return numarray(v.split(' '));
70133                 }
70134
70135                 function gxCoords(root) {
70136                   var elems = get(root, 'coord'),
70137                       coords = [],
70138                       times = [];
70139                   if (elems.length === 0) elems = get(root, 'gx:coord');
70140
70141                   for (var i = 0; i < elems.length; i++) {
70142                     coords.push(gxCoord(nodeVal(elems[i])));
70143                   }
70144
70145                   var timeElems = get(root, 'when');
70146
70147                   for (var j = 0; j < timeElems.length; j++) {
70148                     times.push(nodeVal(timeElems[j]));
70149                   }
70150
70151                   return {
70152                     coords: coords,
70153                     times: times
70154                   };
70155                 }
70156
70157                 function getGeometry(root) {
70158                   var geomNode,
70159                       geomNodes,
70160                       i,
70161                       j,
70162                       k,
70163                       geoms = [],
70164                       coordTimes = [];
70165
70166                   if (get1(root, 'MultiGeometry')) {
70167                     return getGeometry(get1(root, 'MultiGeometry'));
70168                   }
70169
70170                   if (get1(root, 'MultiTrack')) {
70171                     return getGeometry(get1(root, 'MultiTrack'));
70172                   }
70173
70174                   if (get1(root, 'gx:MultiTrack')) {
70175                     return getGeometry(get1(root, 'gx:MultiTrack'));
70176                   }
70177
70178                   for (i = 0; i < geotypes.length; i++) {
70179                     geomNodes = get(root, geotypes[i]);
70180
70181                     if (geomNodes) {
70182                       for (j = 0; j < geomNodes.length; j++) {
70183                         geomNode = geomNodes[j];
70184
70185                         if (geotypes[i] === 'Point') {
70186                           geoms.push({
70187                             type: 'Point',
70188                             coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
70189                           });
70190                         } else if (geotypes[i] === 'LineString') {
70191                           geoms.push({
70192                             type: 'LineString',
70193                             coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
70194                           });
70195                         } else if (geotypes[i] === 'Polygon') {
70196                           var rings = get(geomNode, 'LinearRing'),
70197                               coords = [];
70198
70199                           for (k = 0; k < rings.length; k++) {
70200                             coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
70201                           }
70202
70203                           geoms.push({
70204                             type: 'Polygon',
70205                             coordinates: coords
70206                           });
70207                         } else if (geotypes[i] === 'Track' || geotypes[i] === 'gx:Track') {
70208                           var track = gxCoords(geomNode);
70209                           geoms.push({
70210                             type: 'LineString',
70211                             coordinates: track.coords
70212                           });
70213                           if (track.times.length) coordTimes.push(track.times);
70214                         }
70215                       }
70216                     }
70217                   }
70218
70219                   return {
70220                     geoms: geoms,
70221                     coordTimes: coordTimes
70222                   };
70223                 }
70224
70225                 function getPlacemark(root) {
70226                   var geomsAndTimes = getGeometry(root),
70227                       i,
70228                       properties = {},
70229                       name = nodeVal(get1(root, 'name')),
70230                       address = nodeVal(get1(root, 'address')),
70231                       styleUrl = nodeVal(get1(root, 'styleUrl')),
70232                       description = nodeVal(get1(root, 'description')),
70233                       timeSpan = get1(root, 'TimeSpan'),
70234                       timeStamp = get1(root, 'TimeStamp'),
70235                       extendedData = get1(root, 'ExtendedData'),
70236                       lineStyle = get1(root, 'LineStyle'),
70237                       polyStyle = get1(root, 'PolyStyle'),
70238                       visibility = get1(root, 'visibility');
70239                   if (!geomsAndTimes.geoms.length) return [];
70240                   if (name) properties.name = name;
70241                   if (address) properties.address = address;
70242
70243                   if (styleUrl) {
70244                     if (styleUrl[0] !== '#') {
70245                       styleUrl = '#' + styleUrl;
70246                     }
70247
70248                     properties.styleUrl = styleUrl;
70249
70250                     if (styleIndex[styleUrl]) {
70251                       properties.styleHash = styleIndex[styleUrl];
70252                     }
70253
70254                     if (styleMapIndex[styleUrl]) {
70255                       properties.styleMapHash = styleMapIndex[styleUrl];
70256                       properties.styleHash = styleIndex[styleMapIndex[styleUrl].normal];
70257                     } // Try to populate the lineStyle or polyStyle since we got the style hash
70258
70259
70260                     var style = styleByHash[properties.styleHash];
70261
70262                     if (style) {
70263                       if (!lineStyle) lineStyle = get1(style, 'LineStyle');
70264                       if (!polyStyle) polyStyle = get1(style, 'PolyStyle');
70265                     }
70266                   }
70267
70268                   if (description) properties.description = description;
70269
70270                   if (timeSpan) {
70271                     var begin = nodeVal(get1(timeSpan, 'begin'));
70272                     var end = nodeVal(get1(timeSpan, 'end'));
70273                     properties.timespan = {
70274                       begin: begin,
70275                       end: end
70276                     };
70277                   }
70278
70279                   if (timeStamp) {
70280                     properties.timestamp = nodeVal(get1(timeStamp, 'when'));
70281                   }
70282
70283                   if (lineStyle) {
70284                     var linestyles = kmlColor(nodeVal(get1(lineStyle, 'color'))),
70285                         color = linestyles[0],
70286                         opacity = linestyles[1],
70287                         width = parseFloat(nodeVal(get1(lineStyle, 'width')));
70288                     if (color) properties.stroke = color;
70289                     if (!isNaN(opacity)) properties['stroke-opacity'] = opacity;
70290                     if (!isNaN(width)) properties['stroke-width'] = width;
70291                   }
70292
70293                   if (polyStyle) {
70294                     var polystyles = kmlColor(nodeVal(get1(polyStyle, 'color'))),
70295                         pcolor = polystyles[0],
70296                         popacity = polystyles[1],
70297                         fill = nodeVal(get1(polyStyle, 'fill')),
70298                         outline = nodeVal(get1(polyStyle, 'outline'));
70299                     if (pcolor) properties.fill = pcolor;
70300                     if (!isNaN(popacity)) properties['fill-opacity'] = popacity;
70301                     if (fill) properties['fill-opacity'] = fill === '1' ? properties['fill-opacity'] || 1 : 0;
70302                     if (outline) properties['stroke-opacity'] = outline === '1' ? properties['stroke-opacity'] || 1 : 0;
70303                   }
70304
70305                   if (extendedData) {
70306                     var datas = get(extendedData, 'Data'),
70307                         simpleDatas = get(extendedData, 'SimpleData');
70308
70309                     for (i = 0; i < datas.length; i++) {
70310                       properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
70311                     }
70312
70313                     for (i = 0; i < simpleDatas.length; i++) {
70314                       properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
70315                     }
70316                   }
70317
70318                   if (visibility) {
70319                     properties.visibility = nodeVal(visibility);
70320                   }
70321
70322                   if (geomsAndTimes.coordTimes.length) {
70323                     properties.coordTimes = geomsAndTimes.coordTimes.length === 1 ? geomsAndTimes.coordTimes[0] : geomsAndTimes.coordTimes;
70324                   }
70325
70326                   var feature = {
70327                     type: 'Feature',
70328                     geometry: geomsAndTimes.geoms.length === 1 ? geomsAndTimes.geoms[0] : {
70329                       type: 'GeometryCollection',
70330                       geometries: geomsAndTimes.geoms
70331                     },
70332                     properties: properties
70333                   };
70334                   if (attr(root, 'id')) feature.id = attr(root, 'id');
70335                   return [feature];
70336                 }
70337
70338                 return gj;
70339               },
70340               gpx: function gpx(doc) {
70341                 var i,
70342                     tracks = get(doc, 'trk'),
70343                     routes = get(doc, 'rte'),
70344                     waypoints = get(doc, 'wpt'),
70345                     // a feature collection
70346                 gj = fc(),
70347                     feature;
70348
70349                 for (i = 0; i < tracks.length; i++) {
70350                   feature = getTrack(tracks[i]);
70351                   if (feature) gj.features.push(feature);
70352                 }
70353
70354                 for (i = 0; i < routes.length; i++) {
70355                   feature = getRoute(routes[i]);
70356                   if (feature) gj.features.push(feature);
70357                 }
70358
70359                 for (i = 0; i < waypoints.length; i++) {
70360                   gj.features.push(getPoint(waypoints[i]));
70361                 }
70362
70363                 function getPoints(node, pointname) {
70364                   var pts = get(node, pointname),
70365                       line = [],
70366                       times = [],
70367                       heartRates = [],
70368                       l = pts.length;
70369                   if (l < 2) return {}; // Invalid line in GeoJSON
70370
70371                   for (var i = 0; i < l; i++) {
70372                     var c = coordPair(pts[i]);
70373                     line.push(c.coordinates);
70374                     if (c.time) times.push(c.time);
70375                     if (c.heartRate) heartRates.push(c.heartRate);
70376                   }
70377
70378                   return {
70379                     line: line,
70380                     times: times,
70381                     heartRates: heartRates
70382                   };
70383                 }
70384
70385                 function getTrack(node) {
70386                   var segments = get(node, 'trkseg'),
70387                       track = [],
70388                       times = [],
70389                       heartRates = [],
70390                       line;
70391
70392                   for (var i = 0; i < segments.length; i++) {
70393                     line = getPoints(segments[i], 'trkpt');
70394
70395                     if (line) {
70396                       if (line.line) track.push(line.line);
70397                       if (line.times && line.times.length) times.push(line.times);
70398                       if (line.heartRates && line.heartRates.length) heartRates.push(line.heartRates);
70399                     }
70400                   }
70401
70402                   if (track.length === 0) return;
70403                   var properties = getProperties(node);
70404                   extend(properties, getLineStyle(get1(node, 'extensions')));
70405                   if (times.length) properties.coordTimes = track.length === 1 ? times[0] : times;
70406                   if (heartRates.length) properties.heartRates = track.length === 1 ? heartRates[0] : heartRates;
70407                   return {
70408                     type: 'Feature',
70409                     properties: properties,
70410                     geometry: {
70411                       type: track.length === 1 ? 'LineString' : 'MultiLineString',
70412                       coordinates: track.length === 1 ? track[0] : track
70413                     }
70414                   };
70415                 }
70416
70417                 function getRoute(node) {
70418                   var line = getPoints(node, 'rtept');
70419                   if (!line.line) return;
70420                   var prop = getProperties(node);
70421                   extend(prop, getLineStyle(get1(node, 'extensions')));
70422                   var routeObj = {
70423                     type: 'Feature',
70424                     properties: prop,
70425                     geometry: {
70426                       type: 'LineString',
70427                       coordinates: line.line
70428                     }
70429                   };
70430                   return routeObj;
70431                 }
70432
70433                 function getPoint(node) {
70434                   var prop = getProperties(node);
70435                   extend(prop, getMulti(node, ['sym']));
70436                   return {
70437                     type: 'Feature',
70438                     properties: prop,
70439                     geometry: {
70440                       type: 'Point',
70441                       coordinates: coordPair(node).coordinates
70442                     }
70443                   };
70444                 }
70445
70446                 function getLineStyle(extensions) {
70447                   var style = {};
70448
70449                   if (extensions) {
70450                     var lineStyle = get1(extensions, 'line');
70451
70452                     if (lineStyle) {
70453                       var color = nodeVal(get1(lineStyle, 'color')),
70454                           opacity = parseFloat(nodeVal(get1(lineStyle, 'opacity'))),
70455                           width = parseFloat(nodeVal(get1(lineStyle, 'width')));
70456                       if (color) style.stroke = color;
70457                       if (!isNaN(opacity)) style['stroke-opacity'] = opacity; // GPX width is in mm, convert to px with 96 px per inch
70458
70459                       if (!isNaN(width)) style['stroke-width'] = width * 96 / 25.4;
70460                     }
70461                   }
70462
70463                   return style;
70464                 }
70465
70466                 function getProperties(node) {
70467                   var prop = getMulti(node, ['name', 'cmt', 'desc', 'type', 'time', 'keywords']),
70468                       links = get(node, 'link');
70469                   if (links.length) prop.links = [];
70470
70471                   for (var i = 0, link; i < links.length; i++) {
70472                     link = {
70473                       href: attr(links[i], 'href')
70474                     };
70475                     extend(link, getMulti(links[i], ['text', 'type']));
70476                     prop.links.push(link);
70477                   }
70478
70479                   return prop;
70480                 }
70481
70482                 return gj;
70483               }
70484             };
70485             return t;
70486           }();
70487
70488           module.exports = toGeoJSON;
70489         });
70490
70491         var _initialized = false;
70492         var _enabled = false;
70493
70494         var _geojson;
70495
70496         function svgData(projection, context, dispatch) {
70497           var throttledRedraw = throttle(function () {
70498             dispatch.call('change');
70499           }, 1000);
70500
70501           var _showLabels = true;
70502           var detected = utilDetect();
70503           var layer = select(null);
70504
70505           var _vtService;
70506
70507           var _fileList;
70508
70509           var _template;
70510
70511           var _src;
70512
70513           function init() {
70514             if (_initialized) return; // run once
70515
70516             _geojson = {};
70517             _enabled = true;
70518
70519             function over(d3_event) {
70520               d3_event.stopPropagation();
70521               d3_event.preventDefault();
70522               d3_event.dataTransfer.dropEffect = 'copy';
70523             }
70524
70525             context.container().attr('dropzone', 'copy').on('drop.svgData', function (d3_event) {
70526               d3_event.stopPropagation();
70527               d3_event.preventDefault();
70528               if (!detected.filedrop) return;
70529               drawData.fileList(d3_event.dataTransfer.files);
70530             }).on('dragenter.svgData', over).on('dragexit.svgData', over).on('dragover.svgData', over);
70531             _initialized = true;
70532           }
70533
70534           function getService() {
70535             if (services.vectorTile && !_vtService) {
70536               _vtService = services.vectorTile;
70537
70538               _vtService.event.on('loadedData', throttledRedraw);
70539             } else if (!services.vectorTile && _vtService) {
70540               _vtService = null;
70541             }
70542
70543             return _vtService;
70544           }
70545
70546           function showLayer() {
70547             layerOn();
70548             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
70549               dispatch.call('change');
70550             });
70551           }
70552
70553           function hideLayer() {
70554             throttledRedraw.cancel();
70555             layer.transition().duration(250).style('opacity', 0).on('end', layerOff);
70556           }
70557
70558           function layerOn() {
70559             layer.style('display', 'block');
70560           }
70561
70562           function layerOff() {
70563             layer.selectAll('.viewfield-group').remove();
70564             layer.style('display', 'none');
70565           } // ensure that all geojson features in a collection have IDs
70566
70567
70568           function ensureIDs(gj) {
70569             if (!gj) return null;
70570
70571             if (gj.type === 'FeatureCollection') {
70572               for (var i = 0; i < gj.features.length; i++) {
70573                 ensureFeatureID(gj.features[i]);
70574               }
70575             } else {
70576               ensureFeatureID(gj);
70577             }
70578
70579             return gj;
70580           } // ensure that each single Feature object has a unique ID
70581
70582
70583           function ensureFeatureID(feature) {
70584             if (!feature) return;
70585             feature.__featurehash__ = utilHashcode(fastJsonStableStringify(feature));
70586             return feature;
70587           } // Prefer an array of Features instead of a FeatureCollection
70588
70589
70590           function getFeatures(gj) {
70591             if (!gj) return [];
70592
70593             if (gj.type === 'FeatureCollection') {
70594               return gj.features;
70595             } else {
70596               return [gj];
70597             }
70598           }
70599
70600           function featureKey(d) {
70601             return d.__featurehash__;
70602           }
70603
70604           function isPolygon(d) {
70605             return d.geometry.type === 'Polygon' || d.geometry.type === 'MultiPolygon';
70606           }
70607
70608           function clipPathID(d) {
70609             return 'ideditor-data-' + d.__featurehash__ + '-clippath';
70610           }
70611
70612           function featureClasses(d) {
70613             return ['data' + d.__featurehash__, d.geometry.type, isPolygon(d) ? 'area' : '', d.__layerID__ || ''].filter(Boolean).join(' ');
70614           }
70615
70616           function drawData(selection) {
70617             var vtService = getService();
70618             var getPath = svgPath(projection).geojson;
70619             var getAreaPath = svgPath(projection, null, true).geojson;
70620             var hasData = drawData.hasData();
70621             layer = selection.selectAll('.layer-mapdata').data(_enabled && hasData ? [0] : []);
70622             layer.exit().remove();
70623             layer = layer.enter().append('g').attr('class', 'layer-mapdata').merge(layer);
70624             var surface = context.surface();
70625             if (!surface || surface.empty()) return; // not ready to draw yet, starting up
70626             // Gather data
70627
70628             var geoData, polygonData;
70629
70630             if (_template && vtService) {
70631               // fetch data from vector tile service
70632               var sourceID = _template;
70633               vtService.loadTiles(sourceID, _template, projection);
70634               geoData = vtService.data(sourceID, projection);
70635             } else {
70636               geoData = getFeatures(_geojson);
70637             }
70638
70639             geoData = geoData.filter(getPath);
70640             polygonData = geoData.filter(isPolygon); // Draw clip paths for polygons
70641
70642             var clipPaths = surface.selectAll('defs').selectAll('.clipPath-data').data(polygonData, featureKey);
70643             clipPaths.exit().remove();
70644             var clipPathsEnter = clipPaths.enter().append('clipPath').attr('class', 'clipPath-data').attr('id', clipPathID);
70645             clipPathsEnter.append('path');
70646             clipPaths.merge(clipPathsEnter).selectAll('path').attr('d', getAreaPath); // Draw fill, shadow, stroke layers
70647
70648             var datagroups = layer.selectAll('g.datagroup').data(['fill', 'shadow', 'stroke']);
70649             datagroups = datagroups.enter().append('g').attr('class', function (d) {
70650               return 'datagroup datagroup-' + d;
70651             }).merge(datagroups); // Draw paths
70652
70653             var pathData = {
70654               fill: polygonData,
70655               shadow: geoData,
70656               stroke: geoData
70657             };
70658             var paths = datagroups.selectAll('path').data(function (layer) {
70659               return pathData[layer];
70660             }, featureKey); // exit
70661
70662             paths.exit().remove(); // enter/update
70663
70664             paths = paths.enter().append('path').attr('class', function (d) {
70665               var datagroup = this.parentNode.__data__;
70666               return 'pathdata ' + datagroup + ' ' + featureClasses(d);
70667             }).attr('clip-path', function (d) {
70668               var datagroup = this.parentNode.__data__;
70669               return datagroup === 'fill' ? 'url(#' + clipPathID(d) + ')' : null;
70670             }).merge(paths).attr('d', function (d) {
70671               var datagroup = this.parentNode.__data__;
70672               return datagroup === 'fill' ? getAreaPath(d) : getPath(d);
70673             }); // Draw labels
70674
70675             layer.call(drawLabels, 'label-halo', geoData).call(drawLabels, 'label', geoData);
70676
70677             function drawLabels(selection, textClass, data) {
70678               var labelPath = d3_geoPath(projection);
70679               var labelData = data.filter(function (d) {
70680                 return _showLabels && d.properties && (d.properties.desc || d.properties.name);
70681               });
70682               var labels = selection.selectAll('text.' + textClass).data(labelData, featureKey); // exit
70683
70684               labels.exit().remove(); // enter/update
70685
70686               labels = labels.enter().append('text').attr('class', function (d) {
70687                 return textClass + ' ' + featureClasses(d);
70688               }).merge(labels).text(function (d) {
70689                 return d.properties.desc || d.properties.name;
70690               }).attr('x', function (d) {
70691                 var centroid = labelPath.centroid(d);
70692                 return centroid[0] + 11;
70693               }).attr('y', function (d) {
70694                 var centroid = labelPath.centroid(d);
70695                 return centroid[1];
70696               });
70697             }
70698           }
70699
70700           function getExtension(fileName) {
70701             if (!fileName) return;
70702             var re = /\.(gpx|kml|(geo)?json)$/i;
70703             var match = fileName.toLowerCase().match(re);
70704             return match && match.length && match[0];
70705           }
70706
70707           function xmlToDom(textdata) {
70708             return new DOMParser().parseFromString(textdata, 'text/xml');
70709           }
70710
70711           drawData.setFile = function (extension, data) {
70712             _template = null;
70713             _fileList = null;
70714             _geojson = null;
70715             _src = null;
70716             var gj;
70717
70718             switch (extension) {
70719               case '.gpx':
70720                 gj = togeojson.gpx(xmlToDom(data));
70721                 break;
70722
70723               case '.kml':
70724                 gj = togeojson.kml(xmlToDom(data));
70725                 break;
70726
70727               case '.geojson':
70728               case '.json':
70729                 gj = JSON.parse(data);
70730                 break;
70731             }
70732
70733             gj = gj || {};
70734
70735             if (Object.keys(gj).length) {
70736               _geojson = ensureIDs(gj);
70737               _src = extension + ' data file';
70738               this.fitZoom();
70739             }
70740
70741             dispatch.call('change');
70742             return this;
70743           };
70744
70745           drawData.showLabels = function (val) {
70746             if (!arguments.length) return _showLabels;
70747             _showLabels = val;
70748             return this;
70749           };
70750
70751           drawData.enabled = function (val) {
70752             if (!arguments.length) return _enabled;
70753             _enabled = val;
70754
70755             if (_enabled) {
70756               showLayer();
70757             } else {
70758               hideLayer();
70759             }
70760
70761             dispatch.call('change');
70762             return this;
70763           };
70764
70765           drawData.hasData = function () {
70766             var gj = _geojson || {};
70767             return !!(_template || Object.keys(gj).length);
70768           };
70769
70770           drawData.template = function (val, src) {
70771             if (!arguments.length) return _template; // test source against OSM imagery blocklists..
70772
70773             var osm = context.connection();
70774
70775             if (osm) {
70776               var blocklists = osm.imageryBlocklists();
70777               var fail = false;
70778               var tested = 0;
70779               var regex;
70780
70781               for (var i = 0; i < blocklists.length; i++) {
70782                 regex = blocklists[i];
70783                 fail = regex.test(val);
70784                 tested++;
70785                 if (fail) break;
70786               } // ensure at least one test was run.
70787
70788
70789               if (!tested) {
70790                 regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
70791                 fail = regex.test(val);
70792               }
70793             }
70794
70795             _template = val;
70796             _fileList = null;
70797             _geojson = null; // strip off the querystring/hash from the template,
70798             // it often includes the access token
70799
70800             _src = src || 'vectortile:' + val.split(/[?#]/)[0];
70801             dispatch.call('change');
70802             return this;
70803           };
70804
70805           drawData.geojson = function (gj, src) {
70806             if (!arguments.length) return _geojson;
70807             _template = null;
70808             _fileList = null;
70809             _geojson = null;
70810             _src = null;
70811             gj = gj || {};
70812
70813             if (Object.keys(gj).length) {
70814               _geojson = ensureIDs(gj);
70815               _src = src || 'unknown.geojson';
70816             }
70817
70818             dispatch.call('change');
70819             return this;
70820           };
70821
70822           drawData.fileList = function (fileList) {
70823             if (!arguments.length) return _fileList;
70824             _template = null;
70825             _fileList = fileList;
70826             _geojson = null;
70827             _src = null;
70828             if (!fileList || !fileList.length) return this;
70829             var f = fileList[0];
70830             var extension = getExtension(f.name);
70831             var reader = new FileReader();
70832
70833             reader.onload = function () {
70834               return function (e) {
70835                 drawData.setFile(extension, e.target.result);
70836               };
70837             }();
70838
70839             reader.readAsText(f);
70840             return this;
70841           };
70842
70843           drawData.url = function (url, defaultExtension) {
70844             _template = null;
70845             _fileList = null;
70846             _geojson = null;
70847             _src = null; // strip off any querystring/hash from the url before checking extension
70848
70849             var testUrl = url.split(/[?#]/)[0];
70850             var extension = getExtension(testUrl) || defaultExtension;
70851
70852             if (extension) {
70853               _template = null;
70854               d3_text(url).then(function (data) {
70855                 drawData.setFile(extension, data);
70856               })["catch"](function () {
70857                 /* ignore */
70858               });
70859             } else {
70860               drawData.template(url);
70861             }
70862
70863             return this;
70864           };
70865
70866           drawData.getSrc = function () {
70867             return _src || '';
70868           };
70869
70870           drawData.fitZoom = function () {
70871             var features = getFeatures(_geojson);
70872             if (!features.length) return;
70873             var map = context.map();
70874             var viewport = map.trimmedExtent().polygon();
70875             var coords = features.reduce(function (coords, feature) {
70876               var geom = feature.geometry;
70877               if (!geom) return coords;
70878               var c = geom.coordinates;
70879               /* eslint-disable no-fallthrough */
70880
70881               switch (geom.type) {
70882                 case 'Point':
70883                   c = [c];
70884
70885                 case 'MultiPoint':
70886                 case 'LineString':
70887                   break;
70888
70889                 case 'MultiPolygon':
70890                   c = utilArrayFlatten(c);
70891
70892                 case 'Polygon':
70893                 case 'MultiLineString':
70894                   c = utilArrayFlatten(c);
70895                   break;
70896               }
70897               /* eslint-enable no-fallthrough */
70898
70899
70900               return utilArrayUnion(coords, c);
70901             }, []);
70902
70903             if (!geoPolygonIntersectsPolygon(viewport, coords, true)) {
70904               var extent = geoExtent(d3_geoBounds({
70905                 type: 'LineString',
70906                 coordinates: coords
70907               }));
70908               map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
70909             }
70910
70911             return this;
70912           };
70913
70914           init();
70915           return drawData;
70916         }
70917
70918         function svgDebug(projection, context) {
70919           function drawDebug(selection) {
70920             var showTile = context.getDebug('tile');
70921             var showCollision = context.getDebug('collision');
70922             var showImagery = context.getDebug('imagery');
70923             var showTouchTargets = context.getDebug('target');
70924             var showDownloaded = context.getDebug('downloaded');
70925             var debugData = [];
70926
70927             if (showTile) {
70928               debugData.push({
70929                 "class": 'red',
70930                 label: 'tile'
70931               });
70932             }
70933
70934             if (showCollision) {
70935               debugData.push({
70936                 "class": 'yellow',
70937                 label: 'collision'
70938               });
70939             }
70940
70941             if (showImagery) {
70942               debugData.push({
70943                 "class": 'orange',
70944                 label: 'imagery'
70945               });
70946             }
70947
70948             if (showTouchTargets) {
70949               debugData.push({
70950                 "class": 'pink',
70951                 label: 'touchTargets'
70952               });
70953             }
70954
70955             if (showDownloaded) {
70956               debugData.push({
70957                 "class": 'purple',
70958                 label: 'downloaded'
70959               });
70960             }
70961
70962             var legend = context.container().select('.main-content').selectAll('.debug-legend').data(debugData.length ? [0] : []);
70963             legend.exit().remove();
70964             legend = legend.enter().append('div').attr('class', 'fillD debug-legend').merge(legend);
70965             var legendItems = legend.selectAll('.debug-legend-item').data(debugData, function (d) {
70966               return d.label;
70967             });
70968             legendItems.exit().remove();
70969             legendItems.enter().append('span').attr('class', function (d) {
70970               return "debug-legend-item ".concat(d["class"]);
70971             }).text(function (d) {
70972               return d.label;
70973             });
70974             var layer = selection.selectAll('.layer-debug').data(showImagery || showDownloaded ? [0] : []);
70975             layer.exit().remove();
70976             layer = layer.enter().append('g').attr('class', 'layer-debug').merge(layer); // imagery
70977
70978             var extent = context.map().extent();
70979             _mainFileFetcher.get('imagery').then(function (d) {
70980               var hits = showImagery && d.query.bbox(extent.rectangle(), true) || [];
70981               var features = hits.map(function (d) {
70982                 return d.features[d.id];
70983               });
70984               var imagery = layer.selectAll('path.debug-imagery').data(features);
70985               imagery.exit().remove();
70986               imagery.enter().append('path').attr('class', 'debug-imagery debug orange');
70987             })["catch"](function () {
70988               /* ignore */
70989             }); // downloaded
70990
70991             var osm = context.connection();
70992             var dataDownloaded = [];
70993
70994             if (osm && showDownloaded) {
70995               var rtree = osm.caches('get').tile.rtree;
70996               dataDownloaded = rtree.all().map(function (bbox) {
70997                 return {
70998                   type: 'Feature',
70999                   properties: {
71000                     id: bbox.id
71001                   },
71002                   geometry: {
71003                     type: 'Polygon',
71004                     coordinates: [[[bbox.minX, bbox.minY], [bbox.minX, bbox.maxY], [bbox.maxX, bbox.maxY], [bbox.maxX, bbox.minY], [bbox.minX, bbox.minY]]]
71005                   }
71006                 };
71007               });
71008             }
71009
71010             var downloaded = layer.selectAll('path.debug-downloaded').data(showDownloaded ? dataDownloaded : []);
71011             downloaded.exit().remove();
71012             downloaded.enter().append('path').attr('class', 'debug-downloaded debug purple'); // update
71013
71014             layer.selectAll('path').attr('d', svgPath(projection).geojson);
71015           } // This looks strange because `enabled` methods on other layers are
71016           // chainable getter/setters, and this one is just a getter.
71017
71018
71019           drawDebug.enabled = function () {
71020             if (!arguments.length) {
71021               return context.getDebug('tile') || context.getDebug('collision') || context.getDebug('imagery') || context.getDebug('target') || context.getDebug('downloaded');
71022             } else {
71023               return this;
71024             }
71025           };
71026
71027           return drawDebug;
71028         }
71029
71030         /*
71031             A standalone SVG element that contains only a `defs` sub-element. To be
71032             used once globally, since defs IDs must be unique within a document.
71033         */
71034
71035         function svgDefs(context) {
71036           var _defsSelection = select(null);
71037
71038           var _spritesheetIds = ['iD-sprite', 'maki-sprite', 'temaki-sprite', 'fa-sprite', 'community-sprite'];
71039
71040           function drawDefs(selection) {
71041             _defsSelection = selection.append('defs'); // add markers
71042
71043             _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
71044             // (they can't inherit it from the line they're attached to),
71045             // so we need to manually define markers for each color of tag
71046             // (also, it's slightly nicer if we can control the
71047             // positioning for different tags)
71048
71049
71050             function addSidedMarker(name, color, offset) {
71051               _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);
71052             }
71053
71054             addSidedMarker('natural', 'rgb(170, 170, 170)', 0); // for a coastline, the arrows are (somewhat unintuitively) on
71055             // the water side, so let's color them blue (with a gap) to
71056             // give a stronger indication
71057
71058             addSidedMarker('coastline', '#77dede', 1);
71059             addSidedMarker('waterway', '#77dede', 1); // barriers have a dashed line, and separating the triangle
71060             // from the line visually suits that
71061
71062             addSidedMarker('barrier', '#ddd', 1);
71063             addSidedMarker('man_made', '#fff', 0);
71064
71065             _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');
71066
71067             _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
71068
71069
71070             var patterns = _defsSelection.selectAll('pattern').data([// pattern name, pattern image name
71071             ['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) {
71072               return 'ideditor-pattern-' + d[0];
71073             }).attr('width', 32).attr('height', 32).attr('patternUnits', 'userSpaceOnUse');
71074
71075             patterns.append('rect').attr('x', 0).attr('y', 0).attr('width', 32).attr('height', 32).attr('class', function (d) {
71076               return 'pattern-color-' + d[0];
71077             });
71078             patterns.append('image').attr('x', 0).attr('y', 0).attr('width', 32).attr('height', 32).attr('xlink:href', function (d) {
71079               return context.imagePath('pattern/' + d[1] + '.png');
71080             }); // add clip paths
71081
71082             _defsSelection.selectAll('clipPath').data([12, 18, 20, 32, 45]).enter().append('clipPath').attr('id', function (d) {
71083               return 'ideditor-clip-square-' + d;
71084             }).append('rect').attr('x', 0).attr('y', 0).attr('width', function (d) {
71085               return d;
71086             }).attr('height', function (d) {
71087               return d;
71088             }); // add symbol spritesheets
71089
71090
71091             addSprites(_spritesheetIds, true);
71092           }
71093
71094           function addSprites(ids, overrideColors) {
71095             _spritesheetIds = utilArrayUniq(_spritesheetIds.concat(ids));
71096
71097             var spritesheets = _defsSelection.selectAll('.spritesheet').data(_spritesheetIds);
71098
71099             spritesheets.enter().append('g').attr('class', function (d) {
71100               return 'spritesheet spritesheet-' + d;
71101             }).each(function (d) {
71102               var url = context.imagePath(d + '.svg');
71103               var node = select(this).node();
71104               svg(url).then(function (svg) {
71105                 node.appendChild(select(svg.documentElement).attr('id', 'ideditor-' + d).node());
71106
71107                 if (overrideColors && d !== 'iD-sprite') {
71108                   // allow icon colors to be overridden..
71109                   select(node).selectAll('path').attr('fill', 'currentColor');
71110                 }
71111               })["catch"](function () {
71112                 /* ignore */
71113               });
71114             });
71115             spritesheets.exit().remove();
71116           }
71117
71118           drawDefs.addSprites = addSprites;
71119           return drawDefs;
71120         }
71121
71122         var _layerEnabled = false;
71123
71124         var _qaService;
71125
71126         function svgKeepRight(projection, context, dispatch) {
71127           var throttledRedraw = throttle(function () {
71128             return dispatch.call('change');
71129           }, 1000);
71130
71131           var minZoom = 12;
71132           var touchLayer = select(null);
71133           var drawLayer = select(null);
71134           var layerVisible = false;
71135
71136           function markerPath(selection, klass) {
71137             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');
71138           } // Loosely-coupled keepRight service for fetching issues.
71139
71140
71141           function getService() {
71142             if (services.keepRight && !_qaService) {
71143               _qaService = services.keepRight;
71144
71145               _qaService.on('loaded', throttledRedraw);
71146             } else if (!services.keepRight && _qaService) {
71147               _qaService = null;
71148             }
71149
71150             return _qaService;
71151           } // Show the markers
71152
71153
71154           function editOn() {
71155             if (!layerVisible) {
71156               layerVisible = true;
71157               drawLayer.style('display', 'block');
71158             }
71159           } // Immediately remove the markers and their touch targets
71160
71161
71162           function editOff() {
71163             if (layerVisible) {
71164               layerVisible = false;
71165               drawLayer.style('display', 'none');
71166               drawLayer.selectAll('.qaItem.keepRight').remove();
71167               touchLayer.selectAll('.qaItem.keepRight').remove();
71168             }
71169           } // Enable the layer.  This shows the markers and transitions them to visible.
71170
71171
71172           function layerOn() {
71173             editOn();
71174             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
71175               return dispatch.call('change');
71176             });
71177           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
71178
71179
71180           function layerOff() {
71181             throttledRedraw.cancel();
71182             drawLayer.interrupt();
71183             touchLayer.selectAll('.qaItem.keepRight').remove();
71184             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
71185               editOff();
71186               dispatch.call('change');
71187             });
71188           } // Update the issue markers
71189
71190
71191           function updateMarkers() {
71192             if (!layerVisible || !_layerEnabled) return;
71193             var service = getService();
71194             var selectedID = context.selectedErrorID();
71195             var data = service ? service.getItems(projection) : [];
71196             var getTransform = svgPointTransform(projection); // Draw markers..
71197
71198             var markers = drawLayer.selectAll('.qaItem.keepRight').data(data, function (d) {
71199               return d.id;
71200             }); // exit
71201
71202             markers.exit().remove(); // enter
71203
71204             var markersEnter = markers.enter().append('g').attr('class', function (d) {
71205               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.parentIssueType);
71206             });
71207             markersEnter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
71208             markersEnter.append('path').call(markerPath, 'shadow');
71209             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
71210
71211             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
71212               return d.id === selectedID;
71213             }).attr('transform', getTransform); // Draw targets..
71214
71215             if (touchLayer.empty()) return;
71216             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
71217             var targets = touchLayer.selectAll('.qaItem.keepRight').data(data, function (d) {
71218               return d.id;
71219             }); // exit
71220
71221             targets.exit().remove(); // enter/update
71222
71223             targets.enter().append('rect').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').merge(targets).sort(sortY).attr('class', function (d) {
71224               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
71225             }).attr('transform', getTransform);
71226
71227             function sortY(a, b) {
71228               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];
71229             }
71230           } // Draw the keepRight layer and schedule loading issues and updating markers.
71231
71232
71233           function drawKeepRight(selection) {
71234             var service = getService();
71235             var surface = context.surface();
71236
71237             if (surface && !surface.empty()) {
71238               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
71239             }
71240
71241             drawLayer = selection.selectAll('.layer-keepRight').data(service ? [0] : []);
71242             drawLayer.exit().remove();
71243             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-keepRight').style('display', _layerEnabled ? 'block' : 'none').merge(drawLayer);
71244
71245             if (_layerEnabled) {
71246               if (service && ~~context.map().zoom() >= minZoom) {
71247                 editOn();
71248                 service.loadIssues(projection);
71249                 updateMarkers();
71250               } else {
71251                 editOff();
71252               }
71253             }
71254           } // Toggles the layer on and off
71255
71256
71257           drawKeepRight.enabled = function (val) {
71258             if (!arguments.length) return _layerEnabled;
71259             _layerEnabled = val;
71260
71261             if (_layerEnabled) {
71262               layerOn();
71263             } else {
71264               layerOff();
71265
71266               if (context.selectedErrorID()) {
71267                 context.enter(modeBrowse(context));
71268               }
71269             }
71270
71271             dispatch.call('change');
71272             return this;
71273           };
71274
71275           drawKeepRight.supported = function () {
71276             return !!getService();
71277           };
71278
71279           return drawKeepRight;
71280         }
71281
71282         function svgGeolocate(projection) {
71283           var layer = select(null);
71284
71285           var _position;
71286
71287           function init() {
71288             if (svgGeolocate.initialized) return; // run once
71289
71290             svgGeolocate.enabled = false;
71291             svgGeolocate.initialized = true;
71292           }
71293
71294           function showLayer() {
71295             layer.style('display', 'block');
71296           }
71297
71298           function hideLayer() {
71299             layer.transition().duration(250).style('opacity', 0);
71300           }
71301
71302           function layerOn() {
71303             layer.style('opacity', 0).transition().duration(250).style('opacity', 1);
71304           }
71305
71306           function layerOff() {
71307             layer.style('display', 'none');
71308           }
71309
71310           function transform(d) {
71311             return svgPointTransform(projection)(d);
71312           }
71313
71314           function accuracy(accuracy, loc) {
71315             // converts accuracy to pixels...
71316             var degreesRadius = geoMetersToLat(accuracy),
71317                 tangentLoc = [loc[0], loc[1] + degreesRadius],
71318                 projectedTangent = projection(tangentLoc),
71319                 projectedLoc = projection([loc[0], loc[1]]); // southern most point will have higher pixel value...
71320
71321             return Math.round(projectedLoc[1] - projectedTangent[1]).toString();
71322           }
71323
71324           function update() {
71325             var geolocation = {
71326               loc: [_position.coords.longitude, _position.coords.latitude]
71327             };
71328             var groups = layer.selectAll('.geolocations').selectAll('.geolocation').data([geolocation]);
71329             groups.exit().remove();
71330             var pointsEnter = groups.enter().append('g').attr('class', 'geolocation');
71331             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');
71332             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');
71333             groups.merge(pointsEnter).attr('transform', transform);
71334             layer.select('.geolocate-radius').attr('r', accuracy(_position.coords.accuracy, geolocation.loc));
71335           }
71336
71337           function drawLocation(selection) {
71338             var enabled = svgGeolocate.enabled;
71339             layer = selection.selectAll('.layer-geolocate').data([0]);
71340             layer.exit().remove();
71341             var layerEnter = layer.enter().append('g').attr('class', 'layer-geolocate').style('display', enabled ? 'block' : 'none');
71342             layerEnter.append('g').attr('class', 'geolocations');
71343             layer = layerEnter.merge(layer);
71344
71345             if (enabled) {
71346               update();
71347             } else {
71348               layerOff();
71349             }
71350           }
71351
71352           drawLocation.enabled = function (position, enabled) {
71353             if (!arguments.length) return svgGeolocate.enabled;
71354             _position = position;
71355             svgGeolocate.enabled = enabled;
71356
71357             if (svgGeolocate.enabled) {
71358               showLayer();
71359               layerOn();
71360             } else {
71361               hideLayer();
71362             }
71363
71364             return this;
71365           };
71366
71367           init();
71368           return drawLocation;
71369         }
71370
71371         function svgLabels(projection, context) {
71372           var path = d3_geoPath(projection);
71373           var detected = utilDetect();
71374           var baselineHack = detected.ie || detected.browser.toLowerCase() === 'edge' || detected.browser.toLowerCase() === 'firefox' && detected.version >= 70;
71375
71376           var _rdrawn = new RBush();
71377
71378           var _rskipped = new RBush();
71379
71380           var _textWidthCache = {};
71381           var _entitybboxes = {}; // Listed from highest to lowest priority
71382
71383           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]];
71384
71385           function shouldSkipIcon(preset) {
71386             var noIcons = ['building', 'landuse', 'natural'];
71387             return noIcons.some(function (s) {
71388               return preset.id.indexOf(s) >= 0;
71389             });
71390           }
71391
71392           function get(array, prop) {
71393             return function (d, i) {
71394               return array[i][prop];
71395             };
71396           }
71397
71398           function textWidth(text, size, elem) {
71399             var c = _textWidthCache[size];
71400             if (!c) c = _textWidthCache[size] = {};
71401
71402             if (c[text]) {
71403               return c[text];
71404             } else if (elem) {
71405               c[text] = elem.getComputedTextLength();
71406               return c[text];
71407             } else {
71408               var str = encodeURIComponent(text).match(/%[CDEFcdef]/g);
71409
71410               if (str === null) {
71411                 return size / 3 * 2 * text.length;
71412               } else {
71413                 return size / 3 * (2 * text.length + str.length);
71414               }
71415             }
71416           }
71417
71418           function drawLinePaths(selection, entities, filter, classes, labels) {
71419             var paths = selection.selectAll('path').filter(filter).data(entities, osmEntity.key); // exit
71420
71421             paths.exit().remove(); // enter/update
71422
71423             paths.enter().append('path').style('stroke-width', get(labels, 'font-size')).attr('id', function (d) {
71424               return 'ideditor-labelpath-' + d.id;
71425             }).attr('class', classes).merge(paths).attr('d', get(labels, 'lineString'));
71426           }
71427
71428           function drawLineLabels(selection, entities, filter, classes, labels) {
71429             var texts = selection.selectAll('text.' + classes).filter(filter).data(entities, osmEntity.key); // exit
71430
71431             texts.exit().remove(); // enter
71432
71433             texts.enter().append('text').attr('class', function (d, i) {
71434               return classes + ' ' + labels[i].classes + ' ' + d.id;
71435             }).attr('dy', baselineHack ? '0.35em' : null).append('textPath').attr('class', 'textpath'); // update
71436
71437             selection.selectAll('text.' + classes).selectAll('.textpath').filter(filter).data(entities, osmEntity.key).attr('startOffset', '50%').attr('xlink:href', function (d) {
71438               return '#ideditor-labelpath-' + d.id;
71439             }).text(utilDisplayNameForPath);
71440           }
71441
71442           function drawPointLabels(selection, entities, filter, classes, labels) {
71443             var texts = selection.selectAll('text.' + classes).filter(filter).data(entities, osmEntity.key); // exit
71444
71445             texts.exit().remove(); // enter/update
71446
71447             texts.enter().append('text').attr('class', function (d, i) {
71448               return classes + ' ' + labels[i].classes + ' ' + d.id;
71449             }).merge(texts).attr('x', get(labels, 'x')).attr('y', get(labels, 'y')).style('text-anchor', get(labels, 'textAnchor')).text(utilDisplayName).each(function (d, i) {
71450               textWidth(utilDisplayName(d), labels[i].height, this);
71451             });
71452           }
71453
71454           function drawAreaLabels(selection, entities, filter, classes, labels) {
71455             entities = entities.filter(hasText);
71456             labels = labels.filter(hasText);
71457             drawPointLabels(selection, entities, filter, classes, labels);
71458
71459             function hasText(d, i) {
71460               return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
71461             }
71462           }
71463
71464           function drawAreaIcons(selection, entities, filter, classes, labels) {
71465             var icons = selection.selectAll('use.' + classes).filter(filter).data(entities, osmEntity.key); // exit
71466
71467             icons.exit().remove(); // enter/update
71468
71469             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) {
71470               var preset = _mainPresetIndex.match(d, context.graph());
71471               var picon = preset && preset.icon;
71472
71473               if (!picon) {
71474                 return '';
71475               } else {
71476                 var isMaki = /^maki-/.test(picon);
71477                 return '#' + picon + (isMaki ? '-15' : '');
71478               }
71479             });
71480           }
71481
71482           function drawCollisionBoxes(selection, rtree, which) {
71483             var classes = 'debug ' + which + ' ' + (which === 'debug-skipped' ? 'orange' : 'yellow');
71484             var gj = [];
71485
71486             if (context.getDebug('collision')) {
71487               gj = rtree.all().map(function (d) {
71488                 return {
71489                   type: 'Polygon',
71490                   coordinates: [[[d.minX, d.minY], [d.maxX, d.minY], [d.maxX, d.maxY], [d.minX, d.maxY], [d.minX, d.minY]]]
71491                 };
71492               });
71493             }
71494
71495             var boxes = selection.selectAll('.' + which).data(gj); // exit
71496
71497             boxes.exit().remove(); // enter/update
71498
71499             boxes.enter().append('path').attr('class', classes).merge(boxes).attr('d', d3_geoPath());
71500           }
71501
71502           function drawLabels(selection, graph, entities, filter, dimensions, fullRedraw) {
71503             var wireframe = context.surface().classed('fill-wireframe');
71504             var zoom = geoScaleToZoom(projection.scale());
71505             var labelable = [];
71506             var renderNodeAs = {};
71507             var i, j, k, entity, geometry;
71508
71509             for (i = 0; i < labelStack.length; i++) {
71510               labelable.push([]);
71511             }
71512
71513             if (fullRedraw) {
71514               _rdrawn.clear();
71515
71516               _rskipped.clear();
71517
71518               _entitybboxes = {};
71519             } else {
71520               for (i = 0; i < entities.length; i++) {
71521                 entity = entities[i];
71522                 var toRemove = [].concat(_entitybboxes[entity.id] || []).concat(_entitybboxes[entity.id + 'I'] || []);
71523
71524                 for (j = 0; j < toRemove.length; j++) {
71525                   _rdrawn.remove(toRemove[j]);
71526
71527                   _rskipped.remove(toRemove[j]);
71528                 }
71529               }
71530             } // Loop through all the entities to do some preprocessing
71531
71532
71533             for (i = 0; i < entities.length; i++) {
71534               entity = entities[i];
71535               geometry = entity.geometry(graph); // Insert collision boxes around interesting points/vertices
71536
71537               if (geometry === 'point' || geometry === 'vertex' && isInterestingVertex(entity)) {
71538                 var hasDirections = entity.directions(graph, projection).length;
71539                 var markerPadding;
71540
71541                 if (!wireframe && geometry === 'point' && !(zoom >= 18 && hasDirections)) {
71542                   renderNodeAs[entity.id] = 'point';
71543                   markerPadding = 20; // extra y for marker height
71544                 } else {
71545                   renderNodeAs[entity.id] = 'vertex';
71546                   markerPadding = 0;
71547                 }
71548
71549                 var coord = projection(entity.loc);
71550                 var nodePadding = 10;
71551                 var bbox = {
71552                   minX: coord[0] - nodePadding,
71553                   minY: coord[1] - nodePadding - markerPadding,
71554                   maxX: coord[0] + nodePadding,
71555                   maxY: coord[1] + nodePadding
71556                 };
71557                 doInsert(bbox, entity.id + 'P');
71558               } // From here on, treat vertices like points
71559
71560
71561               if (geometry === 'vertex') {
71562                 geometry = 'point';
71563               } // Determine which entities are label-able
71564
71565
71566               var preset = geometry === 'area' && _mainPresetIndex.match(entity, graph);
71567               var icon = preset && !shouldSkipIcon(preset) && preset.icon;
71568               if (!icon && !utilDisplayName(entity)) continue;
71569
71570               for (k = 0; k < labelStack.length; k++) {
71571                 var matchGeom = labelStack[k][0];
71572                 var matchKey = labelStack[k][1];
71573                 var matchVal = labelStack[k][2];
71574                 var hasVal = entity.tags[matchKey];
71575
71576                 if (geometry === matchGeom && hasVal && (matchVal === '*' || matchVal === hasVal)) {
71577                   labelable[k].push(entity);
71578                   break;
71579                 }
71580               }
71581             }
71582
71583             var positions = {
71584               point: [],
71585               line: [],
71586               area: []
71587             };
71588             var labelled = {
71589               point: [],
71590               line: [],
71591               area: []
71592             }; // Try and find a valid label for labellable entities
71593
71594             for (k = 0; k < labelable.length; k++) {
71595               var fontSize = labelStack[k][3];
71596
71597               for (i = 0; i < labelable[k].length; i++) {
71598                 entity = labelable[k][i];
71599                 geometry = entity.geometry(graph);
71600                 var getName = geometry === 'line' ? utilDisplayNameForPath : utilDisplayName;
71601                 var name = getName(entity);
71602                 var width = name && textWidth(name, fontSize);
71603                 var p = null;
71604
71605                 if (geometry === 'point' || geometry === 'vertex') {
71606                   // no point or vertex labels in wireframe mode
71607                   // no vertex labels at low zooms (vertices have no icons)
71608                   if (wireframe) continue;
71609                   var renderAs = renderNodeAs[entity.id];
71610                   if (renderAs === 'vertex' && zoom < 17) continue;
71611                   p = getPointLabel(entity, width, fontSize, renderAs);
71612                 } else if (geometry === 'line') {
71613                   p = getLineLabel(entity, width, fontSize);
71614                 } else if (geometry === 'area') {
71615                   p = getAreaLabel(entity, width, fontSize);
71616                 }
71617
71618                 if (p) {
71619                   if (geometry === 'vertex') {
71620                     geometry = 'point';
71621                   } // treat vertex like point
71622
71623
71624                   p.classes = geometry + ' tag-' + labelStack[k][1];
71625                   positions[geometry].push(p);
71626                   labelled[geometry].push(entity);
71627                 }
71628               }
71629             }
71630
71631             function isInterestingVertex(entity) {
71632               var selectedIDs = context.selectedIDs();
71633               return entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || selectedIDs.indexOf(entity.id) !== -1 || graph.parentWays(entity).some(function (parent) {
71634                 return selectedIDs.indexOf(parent.id) !== -1;
71635               });
71636             }
71637
71638             function getPointLabel(entity, width, height, geometry) {
71639               var y = geometry === 'point' ? -12 : 0;
71640               var pointOffsets = {
71641                 ltr: [15, y, 'start'],
71642                 rtl: [-15, y, 'end']
71643               };
71644               var textDirection = _mainLocalizer.textDirection();
71645               var coord = projection(entity.loc);
71646               var textPadding = 2;
71647               var offset = pointOffsets[textDirection];
71648               var p = {
71649                 height: height,
71650                 width: width,
71651                 x: coord[0] + offset[0],
71652                 y: coord[1] + offset[1],
71653                 textAnchor: offset[2]
71654               }; // insert a collision box for the text label..
71655
71656               var bbox;
71657
71658               if (textDirection === 'rtl') {
71659                 bbox = {
71660                   minX: p.x - width - textPadding,
71661                   minY: p.y - height / 2 - textPadding,
71662                   maxX: p.x + textPadding,
71663                   maxY: p.y + height / 2 + textPadding
71664                 };
71665               } else {
71666                 bbox = {
71667                   minX: p.x - textPadding,
71668                   minY: p.y - height / 2 - textPadding,
71669                   maxX: p.x + width + textPadding,
71670                   maxY: p.y + height / 2 + textPadding
71671                 };
71672               }
71673
71674               if (tryInsert([bbox], entity.id, true)) {
71675                 return p;
71676               }
71677             }
71678
71679             function getLineLabel(entity, width, height) {
71680               var viewport = geoExtent(context.projection.clipExtent()).polygon();
71681               var points = graph.childNodes(entity).map(function (node) {
71682                 return projection(node.loc);
71683               });
71684               var length = geoPathLength(points);
71685               if (length < width + 20) return; // % along the line to attempt to place the label
71686
71687               var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70, 25, 75, 20, 80, 15, 95, 10, 90, 5, 95];
71688               var padding = 3;
71689
71690               for (var i = 0; i < lineOffsets.length; i++) {
71691                 var offset = lineOffsets[i];
71692                 var middle = offset / 100 * length;
71693                 var start = middle - width / 2;
71694                 if (start < 0 || start + width > length) continue; // generate subpath and ignore paths that are invalid or don't cross viewport.
71695
71696                 var sub = subpath(points, start, start + width);
71697
71698                 if (!sub || !geoPolygonIntersectsPolygon(viewport, sub, true)) {
71699                   continue;
71700                 }
71701
71702                 var isReverse = reverse(sub);
71703
71704                 if (isReverse) {
71705                   sub = sub.reverse();
71706                 }
71707
71708                 var bboxes = [];
71709                 var boxsize = (height + 2) / 2;
71710
71711                 for (var j = 0; j < sub.length - 1; j++) {
71712                   var a = sub[j];
71713                   var b = sub[j + 1]; // split up the text into small collision boxes
71714
71715                   var num = Math.max(1, Math.floor(geoVecLength(a, b) / boxsize / 2));
71716
71717                   for (var box = 0; box < num; box++) {
71718                     var p = geoVecInterp(a, b, box / num);
71719                     var x0 = p[0] - boxsize - padding;
71720                     var y0 = p[1] - boxsize - padding;
71721                     var x1 = p[0] + boxsize + padding;
71722                     var y1 = p[1] + boxsize + padding;
71723                     bboxes.push({
71724                       minX: Math.min(x0, x1),
71725                       minY: Math.min(y0, y1),
71726                       maxX: Math.max(x0, x1),
71727                       maxY: Math.max(y0, y1)
71728                     });
71729                   }
71730                 }
71731
71732                 if (tryInsert(bboxes, entity.id, false)) {
71733                   // accept this one
71734                   return {
71735                     'font-size': height + 2,
71736                     lineString: lineString(sub),
71737                     startOffset: offset + '%'
71738                   };
71739                 }
71740               }
71741
71742               function reverse(p) {
71743                 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
71744                 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI / 2 && angle > -Math.PI / 2);
71745               }
71746
71747               function lineString(points) {
71748                 return 'M' + points.join('L');
71749               }
71750
71751               function subpath(points, from, to) {
71752                 var sofar = 0;
71753                 var start, end, i0, i1;
71754
71755                 for (var i = 0; i < points.length - 1; i++) {
71756                   var a = points[i];
71757                   var b = points[i + 1];
71758                   var current = geoVecLength(a, b);
71759                   var portion;
71760
71761                   if (!start && sofar + current >= from) {
71762                     portion = (from - sofar) / current;
71763                     start = [a[0] + portion * (b[0] - a[0]), a[1] + portion * (b[1] - a[1])];
71764                     i0 = i + 1;
71765                   }
71766
71767                   if (!end && sofar + current >= to) {
71768                     portion = (to - sofar) / current;
71769                     end = [a[0] + portion * (b[0] - a[0]), a[1] + portion * (b[1] - a[1])];
71770                     i1 = i + 1;
71771                   }
71772
71773                   sofar += current;
71774                 }
71775
71776                 var result = points.slice(i0, i1);
71777                 result.unshift(start);
71778                 result.push(end);
71779                 return result;
71780               }
71781             }
71782
71783             function getAreaLabel(entity, width, height) {
71784               var centroid = path.centroid(entity.asGeoJSON(graph, true));
71785               var extent = entity.extent(graph);
71786               var areaWidth = projection(extent[1])[0] - projection(extent[0])[0];
71787               if (isNaN(centroid[0]) || areaWidth < 20) return;
71788               var preset = _mainPresetIndex.match(entity, context.graph());
71789               var picon = preset && preset.icon;
71790               var iconSize = 17;
71791               var padding = 2;
71792               var p = {};
71793
71794               if (picon) {
71795                 // icon and label..
71796                 if (addIcon()) {
71797                   addLabel(iconSize + padding);
71798                   return p;
71799                 }
71800               } else {
71801                 // label only..
71802                 if (addLabel(0)) {
71803                   return p;
71804                 }
71805               }
71806
71807               function addIcon() {
71808                 var iconX = centroid[0] - iconSize / 2;
71809                 var iconY = centroid[1] - iconSize / 2;
71810                 var bbox = {
71811                   minX: iconX,
71812                   minY: iconY,
71813                   maxX: iconX + iconSize,
71814                   maxY: iconY + iconSize
71815                 };
71816
71817                 if (tryInsert([bbox], entity.id + 'I', true)) {
71818                   p.transform = 'translate(' + iconX + ',' + iconY + ')';
71819                   return true;
71820                 }
71821
71822                 return false;
71823               }
71824
71825               function addLabel(yOffset) {
71826                 if (width && areaWidth >= width + 20) {
71827                   var labelX = centroid[0];
71828                   var labelY = centroid[1] + yOffset;
71829                   var bbox = {
71830                     minX: labelX - width / 2 - padding,
71831                     minY: labelY - height / 2 - padding,
71832                     maxX: labelX + width / 2 + padding,
71833                     maxY: labelY + height / 2 + padding
71834                   };
71835
71836                   if (tryInsert([bbox], entity.id, true)) {
71837                     p.x = labelX;
71838                     p.y = labelY;
71839                     p.textAnchor = 'middle';
71840                     p.height = height;
71841                     return true;
71842                   }
71843                 }
71844
71845                 return false;
71846               }
71847             } // force insert a singular bounding box
71848             // singular box only, no array, id better be unique
71849
71850
71851             function doInsert(bbox, id) {
71852               bbox.id = id;
71853               var oldbox = _entitybboxes[id];
71854
71855               if (oldbox) {
71856                 _rdrawn.remove(oldbox);
71857               }
71858
71859               _entitybboxes[id] = bbox;
71860
71861               _rdrawn.insert(bbox);
71862             }
71863
71864             function tryInsert(bboxes, id, saveSkipped) {
71865               var skipped = false;
71866
71867               for (var i = 0; i < bboxes.length; i++) {
71868                 var bbox = bboxes[i];
71869                 bbox.id = id; // Check that label is visible
71870
71871                 if (bbox.minX < 0 || bbox.minY < 0 || bbox.maxX > dimensions[0] || bbox.maxY > dimensions[1]) {
71872                   skipped = true;
71873                   break;
71874                 }
71875
71876                 if (_rdrawn.collides(bbox)) {
71877                   skipped = true;
71878                   break;
71879                 }
71880               }
71881
71882               _entitybboxes[id] = bboxes;
71883
71884               if (skipped) {
71885                 if (saveSkipped) {
71886                   _rskipped.load(bboxes);
71887                 }
71888               } else {
71889                 _rdrawn.load(bboxes);
71890               }
71891
71892               return !skipped;
71893             }
71894
71895             var layer = selection.selectAll('.layer-osm.labels');
71896             layer.selectAll('.labels-group').data(['halo', 'label', 'debug']).enter().append('g').attr('class', function (d) {
71897               return 'labels-group ' + d;
71898             });
71899             var halo = layer.selectAll('.labels-group.halo');
71900             var label = layer.selectAll('.labels-group.label');
71901             var debug = layer.selectAll('.labels-group.debug'); // points
71902
71903             drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
71904             drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point); // lines
71905
71906             drawLinePaths(layer, labelled.line, filter, '', positions.line);
71907             drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
71908             drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line); // areas
71909
71910             drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
71911             drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
71912             drawAreaIcons(label, labelled.area, filter, 'areaicon', positions.area);
71913             drawAreaIcons(halo, labelled.area, filter, 'areaicon-halo', positions.area); // debug
71914
71915             drawCollisionBoxes(debug, _rskipped, 'debug-skipped');
71916             drawCollisionBoxes(debug, _rdrawn, 'debug-drawn');
71917             layer.call(filterLabels);
71918           }
71919
71920           function filterLabels(selection) {
71921             var drawLayer = selection.selectAll('.layer-osm.labels');
71922             var layers = drawLayer.selectAll('.labels-group.halo, .labels-group.label');
71923             layers.selectAll('.nolabel').classed('nolabel', false);
71924             var mouse = context.map().mouse();
71925             var graph = context.graph();
71926             var selectedIDs = context.selectedIDs();
71927             var ids = [];
71928             var pad, bbox; // hide labels near the mouse
71929
71930             if (mouse) {
71931               pad = 20;
71932               bbox = {
71933                 minX: mouse[0] - pad,
71934                 minY: mouse[1] - pad,
71935                 maxX: mouse[0] + pad,
71936                 maxY: mouse[1] + pad
71937               };
71938
71939               var nearMouse = _rdrawn.search(bbox).map(function (entity) {
71940                 return entity.id;
71941               });
71942
71943               ids.push.apply(ids, nearMouse);
71944             } // hide labels on selected nodes (they look weird when dragging / haloed)
71945
71946
71947             for (var i = 0; i < selectedIDs.length; i++) {
71948               var entity = graph.hasEntity(selectedIDs[i]);
71949
71950               if (entity && entity.type === 'node') {
71951                 ids.push(selectedIDs[i]);
71952               }
71953             }
71954
71955             layers.selectAll(utilEntitySelector(ids)).classed('nolabel', true); // draw the mouse bbox if debugging is on..
71956
71957             var debug = selection.selectAll('.labels-group.debug');
71958             var gj = [];
71959
71960             if (context.getDebug('collision')) {
71961               gj = bbox ? [{
71962                 type: 'Polygon',
71963                 coordinates: [[[bbox.minX, bbox.minY], [bbox.maxX, bbox.minY], [bbox.maxX, bbox.maxY], [bbox.minX, bbox.maxY], [bbox.minX, bbox.minY]]]
71964               }] : [];
71965             }
71966
71967             var box = debug.selectAll('.debug-mouse').data(gj); // exit
71968
71969             box.exit().remove(); // enter/update
71970
71971             box.enter().append('path').attr('class', 'debug debug-mouse yellow').merge(box).attr('d', d3_geoPath());
71972           }
71973
71974           var throttleFilterLabels = throttle(filterLabels, 100);
71975
71976           drawLabels.observe = function (selection) {
71977             var listener = function listener() {
71978               throttleFilterLabels(selection);
71979             };
71980
71981             selection.on('mousemove.hidelabels', listener);
71982             context.on('enter.hidelabels', listener);
71983           };
71984
71985           drawLabels.off = function (selection) {
71986             throttleFilterLabels.cancel();
71987             selection.on('mousemove.hidelabels', null);
71988             context.on('enter.hidelabels', null);
71989           };
71990
71991           return drawLabels;
71992         }
71993
71994         var _layerEnabled$1 = false;
71995
71996         var _qaService$1;
71997
71998         function svgImproveOSM(projection, context, dispatch) {
71999           var throttledRedraw = throttle(function () {
72000             return dispatch.call('change');
72001           }, 1000);
72002
72003           var minZoom = 12;
72004           var touchLayer = select(null);
72005           var drawLayer = select(null);
72006           var layerVisible = false;
72007
72008           function markerPath(selection, klass) {
72009             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');
72010           } // Loosely-coupled improveOSM service for fetching issues
72011
72012
72013           function getService() {
72014             if (services.improveOSM && !_qaService$1) {
72015               _qaService$1 = services.improveOSM;
72016
72017               _qaService$1.on('loaded', throttledRedraw);
72018             } else if (!services.improveOSM && _qaService$1) {
72019               _qaService$1 = null;
72020             }
72021
72022             return _qaService$1;
72023           } // Show the markers
72024
72025
72026           function editOn() {
72027             if (!layerVisible) {
72028               layerVisible = true;
72029               drawLayer.style('display', 'block');
72030             }
72031           } // Immediately remove the markers and their touch targets
72032
72033
72034           function editOff() {
72035             if (layerVisible) {
72036               layerVisible = false;
72037               drawLayer.style('display', 'none');
72038               drawLayer.selectAll('.qaItem.improveOSM').remove();
72039               touchLayer.selectAll('.qaItem.improveOSM').remove();
72040             }
72041           } // Enable the layer.  This shows the markers and transitions them to visible.
72042
72043
72044           function layerOn() {
72045             editOn();
72046             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
72047               return dispatch.call('change');
72048             });
72049           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
72050
72051
72052           function layerOff() {
72053             throttledRedraw.cancel();
72054             drawLayer.interrupt();
72055             touchLayer.selectAll('.qaItem.improveOSM').remove();
72056             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
72057               editOff();
72058               dispatch.call('change');
72059             });
72060           } // Update the issue markers
72061
72062
72063           function updateMarkers() {
72064             if (!layerVisible || !_layerEnabled$1) return;
72065             var service = getService();
72066             var selectedID = context.selectedErrorID();
72067             var data = service ? service.getItems(projection) : [];
72068             var getTransform = svgPointTransform(projection); // Draw markers..
72069
72070             var markers = drawLayer.selectAll('.qaItem.improveOSM').data(data, function (d) {
72071               return d.id;
72072             }); // exit
72073
72074             markers.exit().remove(); // enter
72075
72076             var markersEnter = markers.enter().append('g').attr('class', function (d) {
72077               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
72078             });
72079             markersEnter.append('polygon').call(markerPath, 'shadow');
72080             markersEnter.append('ellipse').attr('cx', 0).attr('cy', 0).attr('rx', 4.5).attr('ry', 2).attr('class', 'stroke');
72081             markersEnter.append('polygon').attr('fill', 'currentColor').call(markerPath, 'qaItem-fill');
72082             markersEnter.append('use').attr('transform', 'translate(-6.5, -23)').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('xlink:href', function (d) {
72083               var picon = d.icon;
72084
72085               if (!picon) {
72086                 return '';
72087               } else {
72088                 var isMaki = /^maki-/.test(picon);
72089                 return "#".concat(picon).concat(isMaki ? '-11' : '');
72090               }
72091             }); // update
72092
72093             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
72094               return d.id === selectedID;
72095             }).attr('transform', getTransform); // Draw targets..
72096
72097             if (touchLayer.empty()) return;
72098             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
72099             var targets = touchLayer.selectAll('.qaItem.improveOSM').data(data, function (d) {
72100               return d.id;
72101             }); // exit
72102
72103             targets.exit().remove(); // enter/update
72104
72105             targets.enter().append('rect').attr('width', '20px').attr('height', '30px').attr('x', '-10px').attr('y', '-28px').merge(targets).sort(sortY).attr('class', function (d) {
72106               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
72107             }).attr('transform', getTransform);
72108
72109             function sortY(a, b) {
72110               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
72111             }
72112           } // Draw the ImproveOSM layer and schedule loading issues and updating markers.
72113
72114
72115           function drawImproveOSM(selection) {
72116             var service = getService();
72117             var surface = context.surface();
72118
72119             if (surface && !surface.empty()) {
72120               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
72121             }
72122
72123             drawLayer = selection.selectAll('.layer-improveOSM').data(service ? [0] : []);
72124             drawLayer.exit().remove();
72125             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-improveOSM').style('display', _layerEnabled$1 ? 'block' : 'none').merge(drawLayer);
72126
72127             if (_layerEnabled$1) {
72128               if (service && ~~context.map().zoom() >= minZoom) {
72129                 editOn();
72130                 service.loadIssues(projection);
72131                 updateMarkers();
72132               } else {
72133                 editOff();
72134               }
72135             }
72136           } // Toggles the layer on and off
72137
72138
72139           drawImproveOSM.enabled = function (val) {
72140             if (!arguments.length) return _layerEnabled$1;
72141             _layerEnabled$1 = val;
72142
72143             if (_layerEnabled$1) {
72144               layerOn();
72145             } else {
72146               layerOff();
72147
72148               if (context.selectedErrorID()) {
72149                 context.enter(modeBrowse(context));
72150               }
72151             }
72152
72153             dispatch.call('change');
72154             return this;
72155           };
72156
72157           drawImproveOSM.supported = function () {
72158             return !!getService();
72159           };
72160
72161           return drawImproveOSM;
72162         }
72163
72164         var _layerEnabled$2 = false;
72165
72166         var _qaService$2;
72167
72168         function svgOsmose(projection, context, dispatch) {
72169           var throttledRedraw = throttle(function () {
72170             return dispatch.call('change');
72171           }, 1000);
72172
72173           var minZoom = 12;
72174           var touchLayer = select(null);
72175           var drawLayer = select(null);
72176           var layerVisible = false;
72177
72178           function markerPath(selection, klass) {
72179             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');
72180           } // Loosely-coupled osmose service for fetching issues
72181
72182
72183           function getService() {
72184             if (services.osmose && !_qaService$2) {
72185               _qaService$2 = services.osmose;
72186
72187               _qaService$2.on('loaded', throttledRedraw);
72188             } else if (!services.osmose && _qaService$2) {
72189               _qaService$2 = null;
72190             }
72191
72192             return _qaService$2;
72193           } // Show the markers
72194
72195
72196           function editOn() {
72197             if (!layerVisible) {
72198               layerVisible = true;
72199               drawLayer.style('display', 'block');
72200             }
72201           } // Immediately remove the markers and their touch targets
72202
72203
72204           function editOff() {
72205             if (layerVisible) {
72206               layerVisible = false;
72207               drawLayer.style('display', 'none');
72208               drawLayer.selectAll('.qaItem.osmose').remove();
72209               touchLayer.selectAll('.qaItem.osmose').remove();
72210             }
72211           } // Enable the layer.  This shows the markers and transitions them to visible.
72212
72213
72214           function layerOn() {
72215             editOn();
72216             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
72217               return dispatch.call('change');
72218             });
72219           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
72220
72221
72222           function layerOff() {
72223             throttledRedraw.cancel();
72224             drawLayer.interrupt();
72225             touchLayer.selectAll('.qaItem.osmose').remove();
72226             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
72227               editOff();
72228               dispatch.call('change');
72229             });
72230           } // Update the issue markers
72231
72232
72233           function updateMarkers() {
72234             if (!layerVisible || !_layerEnabled$2) return;
72235             var service = getService();
72236             var selectedID = context.selectedErrorID();
72237             var data = service ? service.getItems(projection) : [];
72238             var getTransform = svgPointTransform(projection); // Draw markers..
72239
72240             var markers = drawLayer.selectAll('.qaItem.osmose').data(data, function (d) {
72241               return d.id;
72242             }); // exit
72243
72244             markers.exit().remove(); // enter
72245
72246             var markersEnter = markers.enter().append('g').attr('class', function (d) {
72247               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
72248             });
72249             markersEnter.append('polygon').call(markerPath, 'shadow');
72250             markersEnter.append('ellipse').attr('cx', 0).attr('cy', 0).attr('rx', 4.5).attr('ry', 2).attr('class', 'stroke');
72251             markersEnter.append('polygon').attr('fill', function (d) {
72252               return service.getColor(d.item);
72253             }).call(markerPath, 'qaItem-fill');
72254             markersEnter.append('use').attr('transform', 'translate(-6.5, -23)').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('xlink:href', function (d) {
72255               var picon = d.icon;
72256
72257               if (!picon) {
72258                 return '';
72259               } else {
72260                 var isMaki = /^maki-/.test(picon);
72261                 return "#".concat(picon).concat(isMaki ? '-11' : '');
72262               }
72263             }); // update
72264
72265             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
72266               return d.id === selectedID;
72267             }).attr('transform', getTransform); // Draw targets..
72268
72269             if (touchLayer.empty()) return;
72270             var fillClass = context.getDebug('target') ? 'pink' : 'nocolor';
72271             var targets = touchLayer.selectAll('.qaItem.osmose').data(data, function (d) {
72272               return d.id;
72273             }); // exit
72274
72275             targets.exit().remove(); // enter/update
72276
72277             targets.enter().append('rect').attr('width', '20px').attr('height', '30px').attr('x', '-10px').attr('y', '-28px').merge(targets).sort(sortY).attr('class', function (d) {
72278               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
72279             }).attr('transform', getTransform);
72280
72281             function sortY(a, b) {
72282               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
72283             }
72284           } // Draw the Osmose layer and schedule loading issues and updating markers.
72285
72286
72287           function drawOsmose(selection) {
72288             var service = getService();
72289             var surface = context.surface();
72290
72291             if (surface && !surface.empty()) {
72292               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
72293             }
72294
72295             drawLayer = selection.selectAll('.layer-osmose').data(service ? [0] : []);
72296             drawLayer.exit().remove();
72297             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-osmose').style('display', _layerEnabled$2 ? 'block' : 'none').merge(drawLayer);
72298
72299             if (_layerEnabled$2) {
72300               if (service && ~~context.map().zoom() >= minZoom) {
72301                 editOn();
72302                 service.loadIssues(projection);
72303                 updateMarkers();
72304               } else {
72305                 editOff();
72306               }
72307             }
72308           } // Toggles the layer on and off
72309
72310
72311           drawOsmose.enabled = function (val) {
72312             if (!arguments.length) return _layerEnabled$2;
72313             _layerEnabled$2 = val;
72314
72315             if (_layerEnabled$2) {
72316               // Strings supplied by Osmose fetched before showing layer for first time
72317               // NOTE: Currently no way to change locale in iD at runtime, would need to re-call this method if that's ever implemented
72318               // Also, If layer is toggled quickly multiple requests are sent
72319               getService().loadStrings().then(layerOn)["catch"](function (err) {
72320                 console.log(err); // eslint-disable-line no-console
72321               });
72322             } else {
72323               layerOff();
72324
72325               if (context.selectedErrorID()) {
72326                 context.enter(modeBrowse(context));
72327               }
72328             }
72329
72330             dispatch.call('change');
72331             return this;
72332           };
72333
72334           drawOsmose.supported = function () {
72335             return !!getService();
72336           };
72337
72338           return drawOsmose;
72339         }
72340
72341         function svgStreetside(projection, context, dispatch) {
72342           var throttledRedraw = throttle(function () {
72343             dispatch.call('change');
72344           }, 1000);
72345
72346           var minZoom = 14;
72347           var minMarkerZoom = 16;
72348           var minViewfieldZoom = 18;
72349           var layer = select(null);
72350           var _viewerYaw = 0;
72351           var _selectedSequence = null;
72352
72353           var _streetside;
72354           /**
72355            * init().
72356            */
72357
72358
72359           function init() {
72360             if (svgStreetside.initialized) return; // run once
72361
72362             svgStreetside.enabled = false;
72363             svgStreetside.initialized = true;
72364           }
72365           /**
72366            * getService().
72367            */
72368
72369
72370           function getService() {
72371             if (services.streetside && !_streetside) {
72372               _streetside = services.streetside;
72373
72374               _streetside.event.on('viewerChanged.svgStreetside', viewerChanged).on('loadedImages.svgStreetside', throttledRedraw);
72375             } else if (!services.streetside && _streetside) {
72376               _streetside = null;
72377             }
72378
72379             return _streetside;
72380           }
72381           /**
72382            * showLayer().
72383            */
72384
72385
72386           function showLayer() {
72387             var service = getService();
72388             if (!service) return;
72389             editOn();
72390             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
72391               dispatch.call('change');
72392             });
72393           }
72394           /**
72395            * hideLayer().
72396            */
72397
72398
72399           function hideLayer() {
72400             throttledRedraw.cancel();
72401             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
72402           }
72403           /**
72404            * editOn().
72405            */
72406
72407
72408           function editOn() {
72409             layer.style('display', 'block');
72410           }
72411           /**
72412            * editOff().
72413            */
72414
72415
72416           function editOff() {
72417             layer.selectAll('.viewfield-group').remove();
72418             layer.style('display', 'none');
72419           }
72420           /**
72421            * click() Handles 'bubble' point click event.
72422            */
72423
72424
72425           function click(d3_event, d) {
72426             var service = getService();
72427             if (!service) return; // try to preserve the viewer rotation when staying on the same sequence
72428
72429             if (d.sequenceKey !== _selectedSequence) {
72430               _viewerYaw = 0; // reset
72431             }
72432
72433             _selectedSequence = d.sequenceKey;
72434             service.ensureViewerLoaded(context).then(function () {
72435               service.selectImage(context, d.key).yaw(_viewerYaw).showViewer(context);
72436             });
72437             context.map().centerEase(d.loc);
72438           }
72439           /**
72440            * mouseover().
72441            */
72442
72443
72444           function mouseover(d3_event, d) {
72445             var service = getService();
72446             if (service) service.setStyles(context, d);
72447           }
72448           /**
72449            * mouseout().
72450            */
72451
72452
72453           function mouseout() {
72454             var service = getService();
72455             if (service) service.setStyles(context, null);
72456           }
72457           /**
72458            * transform().
72459            */
72460
72461
72462           function transform(d) {
72463             var t = svgPointTransform(projection)(d);
72464             var rot = d.ca + _viewerYaw;
72465
72466             if (rot) {
72467               t += ' rotate(' + Math.floor(rot) + ',0,0)';
72468             }
72469
72470             return t;
72471           }
72472
72473           function viewerChanged() {
72474             var service = getService();
72475             if (!service) return;
72476             var viewer = service.viewer();
72477             if (!viewer) return; // update viewfield rotation
72478
72479             _viewerYaw = viewer.getYaw(); // avoid updating if the map is currently transformed
72480             // e.g. during drags or easing.
72481
72482             if (context.map().isTransformed()) return;
72483             layer.selectAll('.viewfield-group.currentView').attr('transform', transform);
72484           }
72485
72486           function filterBubbles(bubbles) {
72487             var fromDate = context.photos().fromDate();
72488             var toDate = context.photos().toDate();
72489             var usernames = context.photos().usernames();
72490
72491             if (fromDate) {
72492               var fromTimestamp = new Date(fromDate).getTime();
72493               bubbles = bubbles.filter(function (bubble) {
72494                 return new Date(bubble.captured_at).getTime() >= fromTimestamp;
72495               });
72496             }
72497
72498             if (toDate) {
72499               var toTimestamp = new Date(toDate).getTime();
72500               bubbles = bubbles.filter(function (bubble) {
72501                 return new Date(bubble.captured_at).getTime() <= toTimestamp;
72502               });
72503             }
72504
72505             if (usernames) {
72506               bubbles = bubbles.filter(function (bubble) {
72507                 return usernames.indexOf(bubble.captured_by) !== -1;
72508               });
72509             }
72510
72511             return bubbles;
72512           }
72513
72514           function filterSequences(sequences) {
72515             var fromDate = context.photos().fromDate();
72516             var toDate = context.photos().toDate();
72517             var usernames = context.photos().usernames();
72518
72519             if (fromDate) {
72520               var fromTimestamp = new Date(fromDate).getTime();
72521               sequences = sequences.filter(function (sequences) {
72522                 return new Date(sequences.properties.captured_at).getTime() >= fromTimestamp;
72523               });
72524             }
72525
72526             if (toDate) {
72527               var toTimestamp = new Date(toDate).getTime();
72528               sequences = sequences.filter(function (sequences) {
72529                 return new Date(sequences.properties.captured_at).getTime() <= toTimestamp;
72530               });
72531             }
72532
72533             if (usernames) {
72534               sequences = sequences.filter(function (sequences) {
72535                 return usernames.indexOf(sequences.properties.captured_by) !== -1;
72536               });
72537             }
72538
72539             return sequences;
72540           }
72541           /**
72542            * update().
72543            */
72544
72545
72546           function update() {
72547             var viewer = context.container().select('.photoviewer');
72548             var selected = viewer.empty() ? undefined : viewer.datum();
72549             var z = ~~context.map().zoom();
72550             var showMarkers = z >= minMarkerZoom;
72551             var showViewfields = z >= minViewfieldZoom;
72552             var service = getService();
72553             var sequences = [];
72554             var bubbles = [];
72555
72556             if (context.photos().showsPanoramic()) {
72557               sequences = service ? service.sequences(projection) : [];
72558               bubbles = service && showMarkers ? service.bubbles(projection) : [];
72559               sequences = filterSequences(sequences);
72560               bubbles = filterBubbles(bubbles);
72561             }
72562
72563             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
72564               return d.properties.key;
72565             }); // exit
72566
72567             traces.exit().remove(); // enter/update
72568
72569             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
72570             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(bubbles, function (d) {
72571               // force reenter once bubbles are attached to a sequence
72572               return d.key + (d.sequenceKey ? 'v1' : 'v0');
72573             }); // exit
72574
72575             groups.exit().remove(); // enter
72576
72577             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
72578             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
72579
72580             var markers = groups.merge(groupsEnter).sort(function (a, b) {
72581               return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1];
72582             }).attr('transform', transform).select('.viewfield-scale');
72583             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
72584             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
72585             viewfields.exit().remove(); // viewfields may or may not be drawn...
72586             // but if they are, draw below the circles
72587
72588             viewfields.enter().insert('path', 'circle').attr('class', 'viewfield').attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
72589
72590             function viewfieldPath() {
72591               var d = this.parentNode.__data__;
72592
72593               if (d.pano) {
72594                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
72595               } else {
72596                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
72597               }
72598             }
72599           }
72600           /**
72601            * drawImages()
72602            * drawImages is the method that is returned (and that runs) every time 'svgStreetside()' is called.
72603            * 'svgStreetside()' is called from index.js
72604            */
72605
72606
72607           function drawImages(selection) {
72608             var enabled = svgStreetside.enabled;
72609             var service = getService();
72610             layer = selection.selectAll('.layer-streetside-images').data(service ? [0] : []);
72611             layer.exit().remove();
72612             var layerEnter = layer.enter().append('g').attr('class', 'layer-streetside-images').style('display', enabled ? 'block' : 'none');
72613             layerEnter.append('g').attr('class', 'sequences');
72614             layerEnter.append('g').attr('class', 'markers');
72615             layer = layerEnter.merge(layer);
72616
72617             if (enabled) {
72618               if (service && ~~context.map().zoom() >= minZoom) {
72619                 editOn();
72620                 update();
72621                 service.loadBubbles(projection);
72622               } else {
72623                 editOff();
72624               }
72625             }
72626           }
72627           /**
72628            * drawImages.enabled().
72629            */
72630
72631
72632           drawImages.enabled = function (_) {
72633             if (!arguments.length) return svgStreetside.enabled;
72634             svgStreetside.enabled = _;
72635
72636             if (svgStreetside.enabled) {
72637               showLayer();
72638               context.photos().on('change.streetside', update);
72639             } else {
72640               hideLayer();
72641               context.photos().on('change.streetside', null);
72642             }
72643
72644             dispatch.call('change');
72645             return this;
72646           };
72647           /**
72648            * drawImages.supported().
72649            */
72650
72651
72652           drawImages.supported = function () {
72653             return !!getService();
72654           };
72655
72656           init();
72657           return drawImages;
72658         }
72659
72660         function svgMapillaryImages(projection, context, dispatch) {
72661           var throttledRedraw = throttle(function () {
72662             dispatch.call('change');
72663           }, 1000);
72664
72665           var minZoom = 12;
72666           var minMarkerZoom = 16;
72667           var minViewfieldZoom = 18;
72668           var layer = select(null);
72669
72670           var _mapillary;
72671
72672           var viewerCompassAngle;
72673
72674           function init() {
72675             if (svgMapillaryImages.initialized) return; // run once
72676
72677             svgMapillaryImages.enabled = false;
72678             svgMapillaryImages.initialized = true;
72679           }
72680
72681           function getService() {
72682             if (services.mapillary && !_mapillary) {
72683               _mapillary = services.mapillary;
72684
72685               _mapillary.event.on('loadedImages', throttledRedraw);
72686             } else if (!services.mapillary && _mapillary) {
72687               _mapillary = null;
72688             }
72689
72690             return _mapillary;
72691           }
72692
72693           function showLayer() {
72694             var service = getService();
72695             if (!service) return;
72696             editOn();
72697             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
72698               dispatch.call('change');
72699             });
72700           }
72701
72702           function hideLayer() {
72703             throttledRedraw.cancel();
72704             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
72705           }
72706
72707           function editOn() {
72708             layer.style('display', 'block');
72709           }
72710
72711           function editOff() {
72712             layer.selectAll('.viewfield-group').remove();
72713             layer.style('display', 'none');
72714           }
72715
72716           function click(d3_event, d) {
72717             var service = getService();
72718             if (!service) return;
72719             service.ensureViewerLoaded(context).then(function () {
72720               service.selectImage(context, d.key).showViewer(context);
72721             });
72722             context.map().centerEase(d.loc);
72723           }
72724
72725           function mouseover(d) {
72726             var service = getService();
72727             if (service) service.setStyles(context, d);
72728           }
72729
72730           function mouseout() {
72731             var service = getService();
72732             if (service) service.setStyles(context, null);
72733           }
72734
72735           function transform(d) {
72736             var t = svgPointTransform(projection)(d);
72737
72738             if (d.pano && viewerCompassAngle !== null && isFinite(viewerCompassAngle)) {
72739               t += ' rotate(' + Math.floor(viewerCompassAngle) + ',0,0)';
72740             } else if (d.ca) {
72741               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
72742             }
72743
72744             return t;
72745           }
72746
72747           function filterImages(images) {
72748             var showsPano = context.photos().showsPanoramic();
72749             var showsFlat = context.photos().showsFlat();
72750             var fromDate = context.photos().fromDate();
72751             var toDate = context.photos().toDate();
72752             var usernames = context.photos().usernames();
72753
72754             if (!showsPano || !showsFlat) {
72755               images = images.filter(function (image) {
72756                 if (image.pano) return showsPano;
72757                 return showsFlat;
72758               });
72759             }
72760
72761             if (fromDate) {
72762               var fromTimestamp = new Date(fromDate).getTime();
72763               images = images.filter(function (image) {
72764                 return new Date(image.captured_at).getTime() >= fromTimestamp;
72765               });
72766             }
72767
72768             if (toDate) {
72769               var toTimestamp = new Date(toDate).getTime();
72770               images = images.filter(function (image) {
72771                 return new Date(image.captured_at).getTime() <= toTimestamp;
72772               });
72773             }
72774
72775             if (usernames) {
72776               images = images.filter(function (image) {
72777                 return usernames.indexOf(image.captured_by) !== -1;
72778               });
72779             }
72780
72781             return images;
72782           }
72783
72784           function filterSequences(sequences, service) {
72785             var showsPano = context.photos().showsPanoramic();
72786             var showsFlat = context.photos().showsFlat();
72787             var fromDate = context.photos().fromDate();
72788             var toDate = context.photos().toDate();
72789             var usernames = context.photos().usernames();
72790
72791             if (!showsPano || !showsFlat) {
72792               sequences = sequences.filter(function (sequence) {
72793                 if (sequence.properties.hasOwnProperty('pano')) {
72794                   if (sequence.properties.pano) return showsPano;
72795                   return showsFlat;
72796                 } else {
72797                   // if the sequence doesn't specify pano or not, search its images
72798                   var cProps = sequence.properties.coordinateProperties;
72799
72800                   if (cProps && cProps.image_keys && cProps.image_keys.length > 0) {
72801                     for (var index in cProps.image_keys) {
72802                       var imageKey = cProps.image_keys[index];
72803                       var image = service.cachedImage(imageKey);
72804
72805                       if (image && image.hasOwnProperty('pano')) {
72806                         if (image.pano) return showsPano;
72807                         return showsFlat;
72808                       }
72809                     }
72810                   }
72811                 }
72812
72813                 return false;
72814               });
72815             }
72816
72817             if (fromDate) {
72818               var fromTimestamp = new Date(fromDate).getTime();
72819               sequences = sequences.filter(function (sequence) {
72820                 return new Date(sequence.properties.captured_at).getTime() >= fromTimestamp;
72821               });
72822             }
72823
72824             if (toDate) {
72825               var toTimestamp = new Date(toDate).getTime();
72826               sequences = sequences.filter(function (sequence) {
72827                 return new Date(sequence.properties.captured_at).getTime() <= toTimestamp;
72828               });
72829             }
72830
72831             if (usernames) {
72832               sequences = sequences.filter(function (sequence) {
72833                 return usernames.indexOf(sequence.properties.username) !== -1;
72834               });
72835             }
72836
72837             return sequences;
72838           }
72839
72840           function update() {
72841             var z = ~~context.map().zoom();
72842             var showMarkers = z >= minMarkerZoom;
72843             var showViewfields = z >= minViewfieldZoom;
72844             var service = getService();
72845             var sequences = service ? service.sequences(projection) : [];
72846             var images = service && showMarkers ? service.images(projection) : [];
72847             images = filterImages(images);
72848             sequences = filterSequences(sequences, service);
72849             service.filterViewer(context);
72850             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
72851               return d.properties.key;
72852             }); // exit
72853
72854             traces.exit().remove(); // enter/update
72855
72856             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
72857             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(images, function (d) {
72858               return d.key;
72859             }); // exit
72860
72861             groups.exit().remove(); // enter
72862
72863             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
72864             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
72865
72866             var markers = groups.merge(groupsEnter).sort(function (a, b) {
72867               return b.loc[1] - a.loc[1]; // sort Y
72868             }).attr('transform', transform).select('.viewfield-scale');
72869             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
72870             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
72871             viewfields.exit().remove();
72872             viewfields.enter() // viewfields may or may not be drawn...
72873             .insert('path', 'circle') // but if they are, draw below the circles
72874             .attr('class', 'viewfield').classed('pano', function () {
72875               return this.parentNode.__data__.pano;
72876             }).attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
72877
72878             function viewfieldPath() {
72879               var d = this.parentNode.__data__;
72880
72881               if (d.pano) {
72882                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
72883               } else {
72884                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
72885               }
72886             }
72887           }
72888
72889           function drawImages(selection) {
72890             var enabled = svgMapillaryImages.enabled;
72891             var service = getService();
72892             layer = selection.selectAll('.layer-mapillary').data(service ? [0] : []);
72893             layer.exit().remove();
72894             var layerEnter = layer.enter().append('g').attr('class', 'layer-mapillary').style('display', enabled ? 'block' : 'none');
72895             layerEnter.append('g').attr('class', 'sequences');
72896             layerEnter.append('g').attr('class', 'markers');
72897             layer = layerEnter.merge(layer);
72898
72899             if (enabled) {
72900               if (service && ~~context.map().zoom() >= minZoom) {
72901                 editOn();
72902                 update();
72903                 service.loadImages(projection);
72904               } else {
72905                 editOff();
72906               }
72907             }
72908           }
72909
72910           drawImages.enabled = function (_) {
72911             if (!arguments.length) return svgMapillaryImages.enabled;
72912             svgMapillaryImages.enabled = _;
72913
72914             if (svgMapillaryImages.enabled) {
72915               showLayer();
72916               context.photos().on('change.mapillary_images', update);
72917             } else {
72918               hideLayer();
72919               context.photos().on('change.mapillary_images', null);
72920             }
72921
72922             dispatch.call('change');
72923             return this;
72924           };
72925
72926           drawImages.supported = function () {
72927             return !!getService();
72928           };
72929
72930           init();
72931           return drawImages;
72932         }
72933
72934         function svgMapillaryPosition(projection, context) {
72935           var throttledRedraw = throttle(function () {
72936             update();
72937           }, 1000);
72938
72939           var minZoom = 12;
72940           var minViewfieldZoom = 18;
72941           var layer = select(null);
72942
72943           var _mapillary;
72944
72945           var viewerCompassAngle;
72946
72947           function init() {
72948             if (svgMapillaryPosition.initialized) return; // run once
72949
72950             svgMapillaryPosition.initialized = true;
72951           }
72952
72953           function getService() {
72954             if (services.mapillary && !_mapillary) {
72955               _mapillary = services.mapillary;
72956
72957               _mapillary.event.on('nodeChanged', throttledRedraw);
72958
72959               _mapillary.event.on('bearingChanged', function (e) {
72960                 viewerCompassAngle = e;
72961                 if (context.map().isTransformed()) return;
72962                 layer.selectAll('.viewfield-group.currentView').filter(function (d) {
72963                   return d.pano;
72964                 }).attr('transform', transform);
72965               });
72966             } else if (!services.mapillary && _mapillary) {
72967               _mapillary = null;
72968             }
72969
72970             return _mapillary;
72971           }
72972
72973           function editOn() {
72974             layer.style('display', 'block');
72975           }
72976
72977           function editOff() {
72978             layer.selectAll('.viewfield-group').remove();
72979             layer.style('display', 'none');
72980           }
72981
72982           function transform(d) {
72983             var t = svgPointTransform(projection)(d);
72984
72985             if (d.pano && viewerCompassAngle !== null && isFinite(viewerCompassAngle)) {
72986               t += ' rotate(' + Math.floor(viewerCompassAngle) + ',0,0)';
72987             } else if (d.ca) {
72988               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
72989             }
72990
72991             return t;
72992           }
72993
72994           function update() {
72995             var z = ~~context.map().zoom();
72996             var showViewfields = z >= minViewfieldZoom;
72997             var service = getService();
72998             var node = service && service.getActiveImage();
72999             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(node ? [node] : [], function (d) {
73000               return d.key;
73001             }); // exit
73002
73003             groups.exit().remove(); // enter
73004
73005             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group currentView highlighted');
73006             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
73007
73008             var markers = groups.merge(groupsEnter).attr('transform', transform).select('.viewfield-scale');
73009             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
73010             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
73011             viewfields.exit().remove();
73012             viewfields.enter().insert('path', 'circle').attr('class', 'viewfield').classed('pano', function () {
73013               return this.parentNode.__data__.pano;
73014             }).attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
73015
73016             function viewfieldPath() {
73017               var d = this.parentNode.__data__;
73018
73019               if (d.pano) {
73020                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
73021               } else {
73022                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
73023               }
73024             }
73025           }
73026
73027           function drawImages(selection) {
73028             var service = getService();
73029             layer = selection.selectAll('.layer-mapillary-position').data(service ? [0] : []);
73030             layer.exit().remove();
73031             var layerEnter = layer.enter().append('g').attr('class', 'layer-mapillary-position');
73032             layerEnter.append('g').attr('class', 'markers');
73033             layer = layerEnter.merge(layer);
73034
73035             if (service && ~~context.map().zoom() >= minZoom) {
73036               editOn();
73037               update();
73038             } else {
73039               editOff();
73040             }
73041           }
73042
73043           drawImages.enabled = function () {
73044             update();
73045             return this;
73046           };
73047
73048           drawImages.supported = function () {
73049             return !!getService();
73050           };
73051
73052           init();
73053           return drawImages;
73054         }
73055
73056         function svgMapillarySigns(projection, context, dispatch) {
73057           var throttledRedraw = throttle(function () {
73058             dispatch.call('change');
73059           }, 1000);
73060
73061           var minZoom = 12;
73062           var layer = select(null);
73063
73064           var _mapillary;
73065
73066           function init() {
73067             if (svgMapillarySigns.initialized) return; // run once
73068
73069             svgMapillarySigns.enabled = false;
73070             svgMapillarySigns.initialized = true;
73071           }
73072
73073           function getService() {
73074             if (services.mapillary && !_mapillary) {
73075               _mapillary = services.mapillary;
73076
73077               _mapillary.event.on('loadedSigns', throttledRedraw);
73078             } else if (!services.mapillary && _mapillary) {
73079               _mapillary = null;
73080             }
73081
73082             return _mapillary;
73083           }
73084
73085           function showLayer() {
73086             var service = getService();
73087             if (!service) return;
73088             service.loadSignResources(context);
73089             editOn();
73090           }
73091
73092           function hideLayer() {
73093             throttledRedraw.cancel();
73094             editOff();
73095           }
73096
73097           function editOn() {
73098             layer.style('display', 'block');
73099           }
73100
73101           function editOff() {
73102             layer.selectAll('.icon-sign').remove();
73103             layer.style('display', 'none');
73104           }
73105
73106           function click(d3_event, d) {
73107             var service = getService();
73108             if (!service) return;
73109             context.map().centerEase(d.loc);
73110             var selectedImageKey = service.getSelectedImageKey();
73111             var imageKey;
73112             var highlightedDetection; // Pick one of the images the sign was detected in,
73113             // preference given to an image already selected.
73114
73115             d.detections.forEach(function (detection) {
73116               if (!imageKey || selectedImageKey === detection.image_key) {
73117                 imageKey = detection.image_key;
73118                 highlightedDetection = detection;
73119               }
73120             });
73121
73122             if (imageKey === selectedImageKey) {
73123               service.highlightDetection(highlightedDetection).selectImage(context, imageKey);
73124             } else {
73125               service.ensureViewerLoaded(context).then(function () {
73126                 service.highlightDetection(highlightedDetection).selectImage(context, imageKey).showViewer(context);
73127               });
73128             }
73129           }
73130
73131           function filterData(detectedFeatures) {
73132             var service = getService();
73133             var fromDate = context.photos().fromDate();
73134             var toDate = context.photos().toDate();
73135             var usernames = context.photos().usernames();
73136
73137             if (fromDate) {
73138               var fromTimestamp = new Date(fromDate).getTime();
73139               detectedFeatures = detectedFeatures.filter(function (feature) {
73140                 return new Date(feature.last_seen_at).getTime() >= fromTimestamp;
73141               });
73142             }
73143
73144             if (toDate) {
73145               var toTimestamp = new Date(toDate).getTime();
73146               detectedFeatures = detectedFeatures.filter(function (feature) {
73147                 return new Date(feature.first_seen_at).getTime() <= toTimestamp;
73148               });
73149             }
73150
73151             if (usernames && service) {
73152               detectedFeatures = detectedFeatures.filter(function (feature) {
73153                 return feature.detections.some(function (detection) {
73154                   var imageKey = detection.image_key;
73155                   var image = service.cachedImage(imageKey);
73156                   return image && usernames.indexOf(image.captured_by) !== -1;
73157                 });
73158               });
73159             }
73160
73161             return detectedFeatures;
73162           }
73163
73164           function update() {
73165             var service = getService();
73166             var data = service ? service.signs(projection) : [];
73167             data = filterData(data);
73168             var selectedImageKey = service.getSelectedImageKey();
73169             var transform = svgPointTransform(projection);
73170             var signs = layer.selectAll('.icon-sign').data(data, function (d) {
73171               return d.key;
73172             }); // exit
73173
73174             signs.exit().remove(); // enter
73175
73176             var enter = signs.enter().append('g').attr('class', 'icon-sign icon-detected').on('click', click);
73177             enter.append('use').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px').attr('xlink:href', function (d) {
73178               return '#' + d.value;
73179             });
73180             enter.append('rect').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px'); // update
73181
73182             signs.merge(enter).attr('transform', transform).classed('currentView', function (d) {
73183               return d.detections.some(function (detection) {
73184                 return detection.image_key === selectedImageKey;
73185               });
73186             }).sort(function (a, b) {
73187               var aSelected = a.detections.some(function (detection) {
73188                 return detection.image_key === selectedImageKey;
73189               });
73190               var bSelected = b.detections.some(function (detection) {
73191                 return detection.image_key === selectedImageKey;
73192               });
73193
73194               if (aSelected === bSelected) {
73195                 return b.loc[1] - a.loc[1]; // sort Y
73196               } else if (aSelected) {
73197                 return 1;
73198               }
73199
73200               return -1;
73201             });
73202           }
73203
73204           function drawSigns(selection) {
73205             var enabled = svgMapillarySigns.enabled;
73206             var service = getService();
73207             layer = selection.selectAll('.layer-mapillary-signs').data(service ? [0] : []);
73208             layer.exit().remove();
73209             layer = layer.enter().append('g').attr('class', 'layer-mapillary-signs layer-mapillary-detections').style('display', enabled ? 'block' : 'none').merge(layer);
73210
73211             if (enabled) {
73212               if (service && ~~context.map().zoom() >= minZoom) {
73213                 editOn();
73214                 update();
73215                 service.loadSigns(projection);
73216                 service.showSignDetections(true);
73217               } else {
73218                 editOff();
73219               }
73220             } else if (service) {
73221               service.showSignDetections(false);
73222             }
73223           }
73224
73225           drawSigns.enabled = function (_) {
73226             if (!arguments.length) return svgMapillarySigns.enabled;
73227             svgMapillarySigns.enabled = _;
73228
73229             if (svgMapillarySigns.enabled) {
73230               showLayer();
73231               context.photos().on('change.mapillary_signs', update);
73232             } else {
73233               hideLayer();
73234               context.photos().on('change.mapillary_signs', null);
73235             }
73236
73237             dispatch.call('change');
73238             return this;
73239           };
73240
73241           drawSigns.supported = function () {
73242             return !!getService();
73243           };
73244
73245           init();
73246           return drawSigns;
73247         }
73248
73249         function svgMapillaryMapFeatures(projection, context, dispatch) {
73250           var throttledRedraw = throttle(function () {
73251             dispatch.call('change');
73252           }, 1000);
73253
73254           var minZoom = 12;
73255           var layer = select(null);
73256
73257           var _mapillary;
73258
73259           function init() {
73260             if (svgMapillaryMapFeatures.initialized) return; // run once
73261
73262             svgMapillaryMapFeatures.enabled = false;
73263             svgMapillaryMapFeatures.initialized = true;
73264           }
73265
73266           function getService() {
73267             if (services.mapillary && !_mapillary) {
73268               _mapillary = services.mapillary;
73269
73270               _mapillary.event.on('loadedMapFeatures', throttledRedraw);
73271             } else if (!services.mapillary && _mapillary) {
73272               _mapillary = null;
73273             }
73274
73275             return _mapillary;
73276           }
73277
73278           function showLayer() {
73279             var service = getService();
73280             if (!service) return;
73281             service.loadObjectResources(context);
73282             editOn();
73283           }
73284
73285           function hideLayer() {
73286             throttledRedraw.cancel();
73287             editOff();
73288           }
73289
73290           function editOn() {
73291             layer.style('display', 'block');
73292           }
73293
73294           function editOff() {
73295             layer.selectAll('.icon-map-feature').remove();
73296             layer.style('display', 'none');
73297           }
73298
73299           function click(d3_event, d) {
73300             var service = getService();
73301             if (!service) return;
73302             context.map().centerEase(d.loc);
73303             var selectedImageKey = service.getSelectedImageKey();
73304             var imageKey;
73305             var highlightedDetection; // Pick one of the images the map feature was detected in,
73306             // preference given to an image already selected.
73307
73308             d.detections.forEach(function (detection) {
73309               if (!imageKey || selectedImageKey === detection.image_key) {
73310                 imageKey = detection.image_key;
73311                 highlightedDetection = detection;
73312               }
73313             });
73314
73315             if (imageKey === selectedImageKey) {
73316               service.highlightDetection(highlightedDetection).selectImage(context, imageKey);
73317             } else {
73318               service.ensureViewerLoaded(context).then(function () {
73319                 service.highlightDetection(highlightedDetection).selectImage(context, imageKey).showViewer(context);
73320               });
73321             }
73322           }
73323
73324           function filterData(detectedFeatures) {
73325             var service = getService();
73326             var fromDate = context.photos().fromDate();
73327             var toDate = context.photos().toDate();
73328             var usernames = context.photos().usernames();
73329
73330             if (fromDate) {
73331               var fromTimestamp = new Date(fromDate).getTime();
73332               detectedFeatures = detectedFeatures.filter(function (feature) {
73333                 return new Date(feature.last_seen_at).getTime() >= fromTimestamp;
73334               });
73335             }
73336
73337             if (toDate) {
73338               var toTimestamp = new Date(toDate).getTime();
73339               detectedFeatures = detectedFeatures.filter(function (feature) {
73340                 return new Date(feature.first_seen_at).getTime() <= toTimestamp;
73341               });
73342             }
73343
73344             if (usernames && service) {
73345               detectedFeatures = detectedFeatures.filter(function (feature) {
73346                 return feature.detections.some(function (detection) {
73347                   var imageKey = detection.image_key;
73348                   var image = service.cachedImage(imageKey);
73349                   return image && usernames.indexOf(image.captured_by) !== -1;
73350                 });
73351               });
73352             }
73353
73354             return detectedFeatures;
73355           }
73356
73357           function update() {
73358             var service = getService();
73359             var data = service ? service.mapFeatures(projection) : [];
73360             data = filterData(data);
73361             var selectedImageKey = service && service.getSelectedImageKey();
73362             var transform = svgPointTransform(projection);
73363             var mapFeatures = layer.selectAll('.icon-map-feature').data(data, function (d) {
73364               return d.key;
73365             }); // exit
73366
73367             mapFeatures.exit().remove(); // enter
73368
73369             var enter = mapFeatures.enter().append('g').attr('class', 'icon-map-feature icon-detected').on('click', click);
73370             enter.append('title').text(function (d) {
73371               var id = d.value.replace(/--/g, '.').replace(/-/g, '_');
73372               return _t('mapillary_map_features.' + id);
73373             });
73374             enter.append('use').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px').attr('xlink:href', function (d) {
73375               if (d.value === 'object--billboard') {
73376                 // no billboard icon right now, so use the advertisement icon
73377                 return '#object--sign--advertisement';
73378               }
73379
73380               return '#' + d.value;
73381             });
73382             enter.append('rect').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px'); // update
73383
73384             mapFeatures.merge(enter).attr('transform', transform).classed('currentView', function (d) {
73385               return d.detections.some(function (detection) {
73386                 return detection.image_key === selectedImageKey;
73387               });
73388             }).sort(function (a, b) {
73389               var aSelected = a.detections.some(function (detection) {
73390                 return detection.image_key === selectedImageKey;
73391               });
73392               var bSelected = b.detections.some(function (detection) {
73393                 return detection.image_key === selectedImageKey;
73394               });
73395
73396               if (aSelected === bSelected) {
73397                 return b.loc[1] - a.loc[1]; // sort Y
73398               } else if (aSelected) {
73399                 return 1;
73400               }
73401
73402               return -1;
73403             });
73404           }
73405
73406           function drawMapFeatures(selection) {
73407             var enabled = svgMapillaryMapFeatures.enabled;
73408             var service = getService();
73409             layer = selection.selectAll('.layer-mapillary-map-features').data(service ? [0] : []);
73410             layer.exit().remove();
73411             layer = layer.enter().append('g').attr('class', 'layer-mapillary-map-features layer-mapillary-detections').style('display', enabled ? 'block' : 'none').merge(layer);
73412
73413             if (enabled) {
73414               if (service && ~~context.map().zoom() >= minZoom) {
73415                 editOn();
73416                 update();
73417                 service.loadMapFeatures(projection);
73418                 service.showFeatureDetections(true);
73419               } else {
73420                 editOff();
73421               }
73422             } else if (service) {
73423               service.showFeatureDetections(false);
73424             }
73425           }
73426
73427           drawMapFeatures.enabled = function (_) {
73428             if (!arguments.length) return svgMapillaryMapFeatures.enabled;
73429             svgMapillaryMapFeatures.enabled = _;
73430
73431             if (svgMapillaryMapFeatures.enabled) {
73432               showLayer();
73433               context.photos().on('change.mapillary_map_features', update);
73434             } else {
73435               hideLayer();
73436               context.photos().on('change.mapillary_map_features', null);
73437             }
73438
73439             dispatch.call('change');
73440             return this;
73441           };
73442
73443           drawMapFeatures.supported = function () {
73444             return !!getService();
73445           };
73446
73447           init();
73448           return drawMapFeatures;
73449         }
73450
73451         function svgOpenstreetcamImages(projection, context, dispatch) {
73452           var throttledRedraw = throttle(function () {
73453             dispatch.call('change');
73454           }, 1000);
73455
73456           var minZoom = 12;
73457           var minMarkerZoom = 16;
73458           var minViewfieldZoom = 18;
73459           var layer = select(null);
73460
73461           var _openstreetcam;
73462
73463           function init() {
73464             if (svgOpenstreetcamImages.initialized) return; // run once
73465
73466             svgOpenstreetcamImages.enabled = false;
73467             svgOpenstreetcamImages.initialized = true;
73468           }
73469
73470           function getService() {
73471             if (services.openstreetcam && !_openstreetcam) {
73472               _openstreetcam = services.openstreetcam;
73473
73474               _openstreetcam.event.on('loadedImages', throttledRedraw);
73475             } else if (!services.openstreetcam && _openstreetcam) {
73476               _openstreetcam = null;
73477             }
73478
73479             return _openstreetcam;
73480           }
73481
73482           function showLayer() {
73483             var service = getService();
73484             if (!service) return;
73485             editOn();
73486             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
73487               dispatch.call('change');
73488             });
73489           }
73490
73491           function hideLayer() {
73492             throttledRedraw.cancel();
73493             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
73494           }
73495
73496           function editOn() {
73497             layer.style('display', 'block');
73498           }
73499
73500           function editOff() {
73501             layer.selectAll('.viewfield-group').remove();
73502             layer.style('display', 'none');
73503           }
73504
73505           function click(d3_event, d) {
73506             var service = getService();
73507             if (!service) return;
73508             service.ensureViewerLoaded(context).then(function () {
73509               service.selectImage(context, d.key).showViewer(context);
73510             });
73511             context.map().centerEase(d.loc);
73512           }
73513
73514           function mouseover(d3_event, d) {
73515             var service = getService();
73516             if (service) service.setStyles(context, d);
73517           }
73518
73519           function mouseout() {
73520             var service = getService();
73521             if (service) service.setStyles(context, null);
73522           }
73523
73524           function transform(d) {
73525             var t = svgPointTransform(projection)(d);
73526
73527             if (d.ca) {
73528               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
73529             }
73530
73531             return t;
73532           }
73533
73534           function filterImages(images) {
73535             var fromDate = context.photos().fromDate();
73536             var toDate = context.photos().toDate();
73537             var usernames = context.photos().usernames();
73538
73539             if (fromDate) {
73540               var fromTimestamp = new Date(fromDate).getTime();
73541               images = images.filter(function (item) {
73542                 return new Date(item.captured_at).getTime() >= fromTimestamp;
73543               });
73544             }
73545
73546             if (toDate) {
73547               var toTimestamp = new Date(toDate).getTime();
73548               images = images.filter(function (item) {
73549                 return new Date(item.captured_at).getTime() <= toTimestamp;
73550               });
73551             }
73552
73553             if (usernames) {
73554               images = images.filter(function (item) {
73555                 return usernames.indexOf(item.captured_by) !== -1;
73556               });
73557             }
73558
73559             return images;
73560           }
73561
73562           function filterSequences(sequences) {
73563             var fromDate = context.photos().fromDate();
73564             var toDate = context.photos().toDate();
73565             var usernames = context.photos().usernames();
73566
73567             if (fromDate) {
73568               var fromTimestamp = new Date(fromDate).getTime();
73569               sequences = sequences.filter(function (image) {
73570                 return new Date(image.properties.captured_at).getTime() >= fromTimestamp;
73571               });
73572             }
73573
73574             if (toDate) {
73575               var toTimestamp = new Date(toDate).getTime();
73576               sequences = sequences.filter(function (image) {
73577                 return new Date(image.properties.captured_at).getTime() <= toTimestamp;
73578               });
73579             }
73580
73581             if (usernames) {
73582               sequences = sequences.filter(function (image) {
73583                 return usernames.indexOf(image.properties.captured_by) !== -1;
73584               });
73585             }
73586
73587             return sequences;
73588           }
73589
73590           function update() {
73591             var viewer = context.container().select('.photoviewer');
73592             var selected = viewer.empty() ? undefined : viewer.datum();
73593             var z = ~~context.map().zoom();
73594             var showMarkers = z >= minMarkerZoom;
73595             var showViewfields = z >= minViewfieldZoom;
73596             var service = getService();
73597             var sequences = [];
73598             var images = [];
73599
73600             if (context.photos().showsFlat()) {
73601               sequences = service ? service.sequences(projection) : [];
73602               images = service && showMarkers ? service.images(projection) : [];
73603               sequences = filterSequences(sequences);
73604               images = filterImages(images);
73605             }
73606
73607             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
73608               return d.properties.key;
73609             }); // exit
73610
73611             traces.exit().remove(); // enter/update
73612
73613             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
73614             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(images, function (d) {
73615               return d.key;
73616             }); // exit
73617
73618             groups.exit().remove(); // enter
73619
73620             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
73621             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
73622
73623             var markers = groups.merge(groupsEnter).sort(function (a, b) {
73624               return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1]; // sort Y
73625             }).attr('transform', transform).select('.viewfield-scale');
73626             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
73627             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
73628             viewfields.exit().remove();
73629             viewfields.enter() // viewfields may or may not be drawn...
73630             .insert('path', 'circle') // but if they are, draw below the circles
73631             .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');
73632           }
73633
73634           function drawImages(selection) {
73635             var enabled = svgOpenstreetcamImages.enabled,
73636                 service = getService();
73637             layer = selection.selectAll('.layer-openstreetcam').data(service ? [0] : []);
73638             layer.exit().remove();
73639             var layerEnter = layer.enter().append('g').attr('class', 'layer-openstreetcam').style('display', enabled ? 'block' : 'none');
73640             layerEnter.append('g').attr('class', 'sequences');
73641             layerEnter.append('g').attr('class', 'markers');
73642             layer = layerEnter.merge(layer);
73643
73644             if (enabled) {
73645               if (service && ~~context.map().zoom() >= minZoom) {
73646                 editOn();
73647                 update();
73648                 service.loadImages(projection);
73649               } else {
73650                 editOff();
73651               }
73652             }
73653           }
73654
73655           drawImages.enabled = function (_) {
73656             if (!arguments.length) return svgOpenstreetcamImages.enabled;
73657             svgOpenstreetcamImages.enabled = _;
73658
73659             if (svgOpenstreetcamImages.enabled) {
73660               showLayer();
73661               context.photos().on('change.openstreetcam_images', update);
73662             } else {
73663               hideLayer();
73664               context.photos().on('change.openstreetcam_images', null);
73665             }
73666
73667             dispatch.call('change');
73668             return this;
73669           };
73670
73671           drawImages.supported = function () {
73672             return !!getService();
73673           };
73674
73675           init();
73676           return drawImages;
73677         }
73678
73679         function svgOsm(projection, context, dispatch) {
73680           var enabled = true;
73681
73682           function drawOsm(selection) {
73683             selection.selectAll('.layer-osm').data(['covered', 'areas', 'lines', 'points', 'labels']).enter().append('g').attr('class', function (d) {
73684               return 'layer-osm ' + d;
73685             });
73686             selection.selectAll('.layer-osm.points').selectAll('.points-group').data(['points', 'midpoints', 'vertices', 'turns']).enter().append('g').attr('class', function (d) {
73687               return 'points-group ' + d;
73688             });
73689           }
73690
73691           function showLayer() {
73692             var layer = context.surface().selectAll('.data-layer.osm');
73693             layer.interrupt();
73694             layer.classed('disabled', false).style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
73695               dispatch.call('change');
73696             });
73697           }
73698
73699           function hideLayer() {
73700             var layer = context.surface().selectAll('.data-layer.osm');
73701             layer.interrupt();
73702             layer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
73703               layer.classed('disabled', true);
73704               dispatch.call('change');
73705             });
73706           }
73707
73708           drawOsm.enabled = function (val) {
73709             if (!arguments.length) return enabled;
73710             enabled = val;
73711
73712             if (enabled) {
73713               showLayer();
73714             } else {
73715               hideLayer();
73716             }
73717
73718             dispatch.call('change');
73719             return this;
73720           };
73721
73722           return drawOsm;
73723         }
73724
73725         var _notesEnabled = false;
73726
73727         var _osmService;
73728
73729         function svgNotes(projection, context, dispatch$1) {
73730           if (!dispatch$1) {
73731             dispatch$1 = dispatch('change');
73732           }
73733
73734           var throttledRedraw = throttle(function () {
73735             dispatch$1.call('change');
73736           }, 1000);
73737
73738           var minZoom = 12;
73739           var touchLayer = select(null);
73740           var drawLayer = select(null);
73741           var _notesVisible = false;
73742
73743           function markerPath(selection, klass) {
73744             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');
73745           } // Loosely-coupled osm service for fetching notes.
73746
73747
73748           function getService() {
73749             if (services.osm && !_osmService) {
73750               _osmService = services.osm;
73751
73752               _osmService.on('loadedNotes', throttledRedraw);
73753             } else if (!services.osm && _osmService) {
73754               _osmService = null;
73755             }
73756
73757             return _osmService;
73758           } // Show the notes
73759
73760
73761           function editOn() {
73762             if (!_notesVisible) {
73763               _notesVisible = true;
73764               drawLayer.style('display', 'block');
73765             }
73766           } // Immediately remove the notes and their touch targets
73767
73768
73769           function editOff() {
73770             if (_notesVisible) {
73771               _notesVisible = false;
73772               drawLayer.style('display', 'none');
73773               drawLayer.selectAll('.note').remove();
73774               touchLayer.selectAll('.note').remove();
73775             }
73776           } // Enable the layer.  This shows the notes and transitions them to visible.
73777
73778
73779           function layerOn() {
73780             editOn();
73781             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
73782               dispatch$1.call('change');
73783             });
73784           } // Disable the layer.  This transitions the layer invisible and then hides the notes.
73785
73786
73787           function layerOff() {
73788             throttledRedraw.cancel();
73789             drawLayer.interrupt();
73790             touchLayer.selectAll('.note').remove();
73791             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
73792               editOff();
73793               dispatch$1.call('change');
73794             });
73795           } // Update the note markers
73796
73797
73798           function updateMarkers() {
73799             if (!_notesVisible || !_notesEnabled) return;
73800             var service = getService();
73801             var selectedID = context.selectedNoteID();
73802             var data = service ? service.notes(projection) : [];
73803             var getTransform = svgPointTransform(projection); // Draw markers..
73804
73805             var notes = drawLayer.selectAll('.note').data(data, function (d) {
73806               return d.status + d.id;
73807             }); // exit
73808
73809             notes.exit().remove(); // enter
73810
73811             var notesEnter = notes.enter().append('g').attr('class', function (d) {
73812               return 'note note-' + d.id + ' ' + d.status;
73813             }).classed('new', function (d) {
73814               return d.id < 0;
73815             });
73816             notesEnter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
73817             notesEnter.append('path').call(markerPath, 'shadow');
73818             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');
73819             notesEnter.selectAll('.icon-annotation').data(function (d) {
73820               return [d];
73821             }).enter().append('use').attr('class', 'icon-annotation').attr('width', '10px').attr('height', '10px').attr('x', '-3px').attr('y', '-19px').attr('xlink:href', function (d) {
73822               return '#iD-icon-' + (d.id < 0 ? 'plus' : d.status === 'open' ? 'close' : 'apply');
73823             }); // update
73824
73825             notes.merge(notesEnter).sort(sortY).classed('selected', function (d) {
73826               var mode = context.mode();
73827               var isMoving = mode && mode.id === 'drag-note'; // no shadows when dragging
73828
73829               return !isMoving && d.id === selectedID;
73830             }).attr('transform', getTransform); // Draw targets..
73831
73832             if (touchLayer.empty()) return;
73833             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
73834             var targets = touchLayer.selectAll('.note').data(data, function (d) {
73835               return d.id;
73836             }); // exit
73837
73838             targets.exit().remove(); // enter/update
73839
73840             targets.enter().append('rect').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').merge(targets).sort(sortY).attr('class', function (d) {
73841               var newClass = d.id < 0 ? 'new' : '';
73842               return 'note target note-' + d.id + ' ' + fillClass + newClass;
73843             }).attr('transform', getTransform);
73844
73845             function sortY(a, b) {
73846               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
73847             }
73848           } // Draw the notes layer and schedule loading notes and updating markers.
73849
73850
73851           function drawNotes(selection) {
73852             var service = getService();
73853             var surface = context.surface();
73854
73855             if (surface && !surface.empty()) {
73856               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
73857             }
73858
73859             drawLayer = selection.selectAll('.layer-notes').data(service ? [0] : []);
73860             drawLayer.exit().remove();
73861             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-notes').style('display', _notesEnabled ? 'block' : 'none').merge(drawLayer);
73862
73863             if (_notesEnabled) {
73864               if (service && ~~context.map().zoom() >= minZoom) {
73865                 editOn();
73866                 service.loadNotes(projection);
73867                 updateMarkers();
73868               } else {
73869                 editOff();
73870               }
73871             }
73872           } // Toggles the layer on and off
73873
73874
73875           drawNotes.enabled = function (val) {
73876             if (!arguments.length) return _notesEnabled;
73877             _notesEnabled = val;
73878
73879             if (_notesEnabled) {
73880               layerOn();
73881             } else {
73882               layerOff();
73883
73884               if (context.selectedNoteID()) {
73885                 context.enter(modeBrowse(context));
73886               }
73887             }
73888
73889             dispatch$1.call('change');
73890             return this;
73891           };
73892
73893           return drawNotes;
73894         }
73895
73896         function svgTouch() {
73897           function drawTouch(selection) {
73898             selection.selectAll('.layer-touch').data(['areas', 'lines', 'points', 'turns', 'markers']).enter().append('g').attr('class', function (d) {
73899               return 'layer-touch ' + d;
73900             });
73901           }
73902
73903           return drawTouch;
73904         }
73905
73906         function refresh(selection, node) {
73907           var cr = node.getBoundingClientRect();
73908           var prop = [cr.width, cr.height];
73909           selection.property('__dimensions__', prop);
73910           return prop;
73911         }
73912
73913         function utilGetDimensions(selection, force) {
73914           if (!selection || selection.empty()) {
73915             return [0, 0];
73916           }
73917
73918           var node = selection.node(),
73919               cached = selection.property('__dimensions__');
73920           return !cached || force ? refresh(selection, node) : cached;
73921         }
73922         function utilSetDimensions(selection, dimensions) {
73923           if (!selection || selection.empty()) {
73924             return selection;
73925           }
73926
73927           var node = selection.node();
73928
73929           if (dimensions === null) {
73930             refresh(selection, node);
73931             return selection;
73932           }
73933
73934           return selection.property('__dimensions__', [dimensions[0], dimensions[1]]).attr('width', dimensions[0]).attr('height', dimensions[1]);
73935         }
73936
73937         function svgLayers(projection, context) {
73938           var dispatch$1 = dispatch('change');
73939           var svg = select(null);
73940           var _layers = [{
73941             id: 'osm',
73942             layer: svgOsm(projection, context, dispatch$1)
73943           }, {
73944             id: 'notes',
73945             layer: svgNotes(projection, context, dispatch$1)
73946           }, {
73947             id: 'data',
73948             layer: svgData(projection, context, dispatch$1)
73949           }, {
73950             id: 'keepRight',
73951             layer: svgKeepRight(projection, context, dispatch$1)
73952           }, {
73953             id: 'improveOSM',
73954             layer: svgImproveOSM(projection, context, dispatch$1)
73955           }, {
73956             id: 'osmose',
73957             layer: svgOsmose(projection, context, dispatch$1)
73958           }, {
73959             id: 'streetside',
73960             layer: svgStreetside(projection, context, dispatch$1)
73961           }, {
73962             id: 'mapillary',
73963             layer: svgMapillaryImages(projection, context, dispatch$1)
73964           }, {
73965             id: 'mapillary-position',
73966             layer: svgMapillaryPosition(projection, context)
73967           }, {
73968             id: 'mapillary-map-features',
73969             layer: svgMapillaryMapFeatures(projection, context, dispatch$1)
73970           }, {
73971             id: 'mapillary-signs',
73972             layer: svgMapillarySigns(projection, context, dispatch$1)
73973           }, {
73974             id: 'openstreetcam',
73975             layer: svgOpenstreetcamImages(projection, context, dispatch$1)
73976           }, {
73977             id: 'debug',
73978             layer: svgDebug(projection, context)
73979           }, {
73980             id: 'geolocate',
73981             layer: svgGeolocate(projection)
73982           }, {
73983             id: 'touch',
73984             layer: svgTouch()
73985           }];
73986
73987           function drawLayers(selection) {
73988             svg = selection.selectAll('.surface').data([0]);
73989             svg = svg.enter().append('svg').attr('class', 'surface').merge(svg);
73990             var defs = svg.selectAll('.surface-defs').data([0]);
73991             defs.enter().append('defs').attr('class', 'surface-defs');
73992             var groups = svg.selectAll('.data-layer').data(_layers);
73993             groups.exit().remove();
73994             groups.enter().append('g').attr('class', function (d) {
73995               return 'data-layer ' + d.id;
73996             }).merge(groups).each(function (d) {
73997               select(this).call(d.layer);
73998             });
73999           }
74000
74001           drawLayers.all = function () {
74002             return _layers;
74003           };
74004
74005           drawLayers.layer = function (id) {
74006             var obj = _layers.find(function (o) {
74007               return o.id === id;
74008             });
74009
74010             return obj && obj.layer;
74011           };
74012
74013           drawLayers.only = function (what) {
74014             var arr = [].concat(what);
74015
74016             var all = _layers.map(function (layer) {
74017               return layer.id;
74018             });
74019
74020             return drawLayers.remove(utilArrayDifference(all, arr));
74021           };
74022
74023           drawLayers.remove = function (what) {
74024             var arr = [].concat(what);
74025             arr.forEach(function (id) {
74026               _layers = _layers.filter(function (o) {
74027                 return o.id !== id;
74028               });
74029             });
74030             dispatch$1.call('change');
74031             return this;
74032           };
74033
74034           drawLayers.add = function (what) {
74035             var arr = [].concat(what);
74036             arr.forEach(function (obj) {
74037               if ('id' in obj && 'layer' in obj) {
74038                 _layers.push(obj);
74039               }
74040             });
74041             dispatch$1.call('change');
74042             return this;
74043           };
74044
74045           drawLayers.dimensions = function (val) {
74046             if (!arguments.length) return utilGetDimensions(svg);
74047             utilSetDimensions(svg, val);
74048             return this;
74049           };
74050
74051           return utilRebind(drawLayers, dispatch$1, 'on');
74052         }
74053
74054         function svgLines(projection, context) {
74055           var detected = utilDetect();
74056           var highway_stack = {
74057             motorway: 0,
74058             motorway_link: 1,
74059             trunk: 2,
74060             trunk_link: 3,
74061             primary: 4,
74062             primary_link: 5,
74063             secondary: 6,
74064             tertiary: 7,
74065             unclassified: 8,
74066             residential: 9,
74067             service: 10,
74068             footway: 11
74069           };
74070
74071           function drawTargets(selection, graph, entities, filter) {
74072             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
74073             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
74074             var getPath = svgPath(projection).geojson;
74075             var activeID = context.activeID();
74076             var base = context.history().base(); // The targets and nopes will be MultiLineString sub-segments of the ways
74077
74078             var data = {
74079               targets: [],
74080               nopes: []
74081             };
74082             entities.forEach(function (way) {
74083               var features = svgSegmentWay(way, graph, activeID);
74084               data.targets.push.apply(data.targets, features.passive);
74085               data.nopes.push.apply(data.nopes, features.active);
74086             }); // Targets allow hover and vertex snapping
74087
74088             var targetData = data.targets.filter(getPath);
74089             var targets = selection.selectAll('.line.target-allowed').filter(function (d) {
74090               return filter(d.properties.entity);
74091             }).data(targetData, function key(d) {
74092               return d.id;
74093             }); // exit
74094
74095             targets.exit().remove();
74096
74097             var segmentWasEdited = function segmentWasEdited(d) {
74098               var wayID = d.properties.entity.id; // if the whole line was edited, don't draw segment changes
74099
74100               if (!base.entities[wayID] || !fastDeepEqual(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
74101                 return false;
74102               }
74103
74104               return d.properties.nodes.some(function (n) {
74105                 return !base.entities[n.id] || !fastDeepEqual(graph.entities[n.id].loc, base.entities[n.id].loc);
74106               });
74107             }; // enter/update
74108
74109
74110             targets.enter().append('path').merge(targets).attr('d', getPath).attr('class', function (d) {
74111               return 'way line target target-allowed ' + targetClass + d.id;
74112             }).classed('segment-edited', segmentWasEdited); // NOPE
74113
74114             var nopeData = data.nopes.filter(getPath);
74115             var nopes = selection.selectAll('.line.target-nope').filter(function (d) {
74116               return filter(d.properties.entity);
74117             }).data(nopeData, function key(d) {
74118               return d.id;
74119             }); // exit
74120
74121             nopes.exit().remove(); // enter/update
74122
74123             nopes.enter().append('path').merge(nopes).attr('d', getPath).attr('class', function (d) {
74124               return 'way line target target-nope ' + nopeClass + d.id;
74125             }).classed('segment-edited', segmentWasEdited);
74126           }
74127
74128           function drawLines(selection, graph, entities, filter) {
74129             var base = context.history().base();
74130
74131             function waystack(a, b) {
74132               var selected = context.selectedIDs();
74133               var scoreA = selected.indexOf(a.id) !== -1 ? 20 : 0;
74134               var scoreB = selected.indexOf(b.id) !== -1 ? 20 : 0;
74135
74136               if (a.tags.highway) {
74137                 scoreA -= highway_stack[a.tags.highway];
74138               }
74139
74140               if (b.tags.highway) {
74141                 scoreB -= highway_stack[b.tags.highway];
74142               }
74143
74144               return scoreA - scoreB;
74145             }
74146
74147             function drawLineGroup(selection, klass, isSelected) {
74148               // Note: Don't add `.selected` class in draw modes
74149               var mode = context.mode();
74150               var isDrawing = mode && /^draw/.test(mode.id);
74151               var selectedClass = !isDrawing && isSelected ? 'selected ' : '';
74152               var lines = selection.selectAll('path').filter(filter).data(getPathData(isSelected), osmEntity.key);
74153               lines.exit().remove(); // Optimization: Call expensive TagClasses only on enter selection. This
74154               // works because osmEntity.key is defined to include the entity v attribute.
74155
74156               lines.enter().append('path').attr('class', function (d) {
74157                 var prefix = 'way line'; // if this line isn't styled by its own tags
74158
74159                 if (!d.hasInterestingTags()) {
74160                   var parentRelations = graph.parentRelations(d);
74161                   var parentMultipolygons = parentRelations.filter(function (relation) {
74162                     return relation.isMultipolygon();
74163                   }); // and if it's a member of at least one multipolygon relation
74164
74165                   if (parentMultipolygons.length > 0 && // and only multipolygon relations
74166                   parentRelations.length === parentMultipolygons.length) {
74167                     // then fudge the classes to style this as an area edge
74168                     prefix = 'relation area';
74169                   }
74170                 }
74171
74172                 var oldMPClass = oldMultiPolygonOuters[d.id] ? 'old-multipolygon ' : '';
74173                 return prefix + ' ' + klass + ' ' + selectedClass + oldMPClass + d.id;
74174               }).classed('added', function (d) {
74175                 return !base.entities[d.id];
74176               }).classed('geometry-edited', function (d) {
74177                 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].nodes, base.entities[d.id].nodes);
74178               }).classed('retagged', function (d) {
74179                 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
74180               }).call(svgTagClasses()).merge(lines).sort(waystack).attr('d', getPath).call(svgTagClasses().tags(svgRelationMemberTags(graph)));
74181               return selection;
74182             }
74183
74184             function getPathData(isSelected) {
74185               return function () {
74186                 var layer = this.parentNode.__data__;
74187                 var data = pathdata[layer] || [];
74188                 return data.filter(function (d) {
74189                   if (isSelected) return context.selectedIDs().indexOf(d.id) !== -1;else return context.selectedIDs().indexOf(d.id) === -1;
74190                 });
74191               };
74192             }
74193
74194             function addMarkers(layergroup, pathclass, groupclass, groupdata, marker) {
74195               var markergroup = layergroup.selectAll('g.' + groupclass).data([pathclass]);
74196               markergroup = markergroup.enter().append('g').attr('class', groupclass).merge(markergroup);
74197               var markers = markergroup.selectAll('path').filter(filter).data(function data() {
74198                 return groupdata[this.parentNode.__data__] || [];
74199               }, function key(d) {
74200                 return [d.id, d.index];
74201               });
74202               markers.exit().remove();
74203               markers = markers.enter().append('path').attr('class', pathclass).merge(markers).attr('marker-mid', marker).attr('d', function (d) {
74204                 return d.d;
74205               });
74206
74207               if (detected.ie) {
74208                 markers.each(function () {
74209                   this.parentNode.insertBefore(this, this);
74210                 });
74211               }
74212             }
74213
74214             var getPath = svgPath(projection, graph);
74215             var ways = [];
74216             var onewaydata = {};
74217             var sideddata = {};
74218             var oldMultiPolygonOuters = {};
74219
74220             for (var i = 0; i < entities.length; i++) {
74221               var entity = entities[i];
74222               var outer = osmOldMultipolygonOuterMember(entity, graph);
74223
74224               if (outer) {
74225                 ways.push(entity.mergeTags(outer.tags));
74226                 oldMultiPolygonOuters[outer.id] = true;
74227               } else if (entity.geometry(graph) === 'line') {
74228                 ways.push(entity);
74229               }
74230             }
74231
74232             ways = ways.filter(getPath);
74233             var pathdata = utilArrayGroupBy(ways, function (way) {
74234               return way.layer();
74235             });
74236             Object.keys(pathdata).forEach(function (k) {
74237               var v = pathdata[k];
74238               var onewayArr = v.filter(function (d) {
74239                 return d.isOneWay();
74240               });
74241               var onewaySegments = svgMarkerSegments(projection, graph, 35, function shouldReverse(entity) {
74242                 return entity.tags.oneway === '-1';
74243               }, function bothDirections(entity) {
74244                 return entity.tags.oneway === 'reversible' || entity.tags.oneway === 'alternating';
74245               });
74246               onewaydata[k] = utilArrayFlatten(onewayArr.map(onewaySegments));
74247               var sidedArr = v.filter(function (d) {
74248                 return d.isSided();
74249               });
74250               var sidedSegments = svgMarkerSegments(projection, graph, 30, function shouldReverse() {
74251                 return false;
74252               }, function bothDirections() {
74253                 return false;
74254               });
74255               sideddata[k] = utilArrayFlatten(sidedArr.map(sidedSegments));
74256             });
74257             var covered = selection.selectAll('.layer-osm.covered'); // under areas
74258
74259             var uncovered = selection.selectAll('.layer-osm.lines'); // over areas
74260
74261             var touchLayer = selection.selectAll('.layer-touch.lines'); // Draw lines..
74262
74263             [covered, uncovered].forEach(function (selection) {
74264               var range$1 = selection === covered ? range(-10, 0) : range(0, 11);
74265               var layergroup = selection.selectAll('g.layergroup').data(range$1);
74266               layergroup = layergroup.enter().append('g').attr('class', function (d) {
74267                 return 'layergroup layer' + String(d);
74268               }).merge(layergroup);
74269               layergroup.selectAll('g.linegroup').data(['shadow', 'casing', 'stroke', 'shadow-highlighted', 'casing-highlighted', 'stroke-highlighted']).enter().append('g').attr('class', function (d) {
74270                 return 'linegroup line-' + d;
74271               });
74272               layergroup.selectAll('g.line-shadow').call(drawLineGroup, 'shadow', false);
74273               layergroup.selectAll('g.line-casing').call(drawLineGroup, 'casing', false);
74274               layergroup.selectAll('g.line-stroke').call(drawLineGroup, 'stroke', false);
74275               layergroup.selectAll('g.line-shadow-highlighted').call(drawLineGroup, 'shadow', true);
74276               layergroup.selectAll('g.line-casing-highlighted').call(drawLineGroup, 'casing', true);
74277               layergroup.selectAll('g.line-stroke-highlighted').call(drawLineGroup, 'stroke', true);
74278               addMarkers(layergroup, 'oneway', 'onewaygroup', onewaydata, 'url(#ideditor-oneway-marker)');
74279               addMarkers(layergroup, 'sided', 'sidedgroup', sideddata, function marker(d) {
74280                 var category = graph.entity(d.id).sidednessIdentifier();
74281                 return 'url(#ideditor-sided-marker-' + category + ')';
74282               });
74283             }); // Draw touch targets..
74284
74285             touchLayer.call(drawTargets, graph, ways, filter);
74286           }
74287
74288           return drawLines;
74289         }
74290
74291         function svgMidpoints(projection, context) {
74292           var targetRadius = 8;
74293
74294           function drawTargets(selection, graph, entities, filter) {
74295             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
74296             var getTransform = svgPointTransform(projection).geojson;
74297             var data = entities.map(function (midpoint) {
74298               return {
74299                 type: 'Feature',
74300                 id: midpoint.id,
74301                 properties: {
74302                   target: true,
74303                   entity: midpoint
74304                 },
74305                 geometry: {
74306                   type: 'Point',
74307                   coordinates: midpoint.loc
74308                 }
74309               };
74310             });
74311             var targets = selection.selectAll('.midpoint.target').filter(function (d) {
74312               return filter(d.properties.entity);
74313             }).data(data, function key(d) {
74314               return d.id;
74315             }); // exit
74316
74317             targets.exit().remove(); // enter/update
74318
74319             targets.enter().append('circle').attr('r', targetRadius).merge(targets).attr('class', function (d) {
74320               return 'node midpoint target ' + fillClass + d.id;
74321             }).attr('transform', getTransform);
74322           }
74323
74324           function drawMidpoints(selection, graph, entities, filter, extent) {
74325             var drawLayer = selection.selectAll('.layer-osm.points .points-group.midpoints');
74326             var touchLayer = selection.selectAll('.layer-touch.points');
74327             var mode = context.mode();
74328
74329             if (mode && mode.id !== 'select' || !context.map().withinEditableZoom()) {
74330               drawLayer.selectAll('.midpoint').remove();
74331               touchLayer.selectAll('.midpoint.target').remove();
74332               return;
74333             }
74334
74335             var poly = extent.polygon();
74336             var midpoints = {};
74337
74338             for (var i = 0; i < entities.length; i++) {
74339               var entity = entities[i];
74340               if (entity.type !== 'way') continue;
74341               if (!filter(entity)) continue;
74342               if (context.selectedIDs().indexOf(entity.id) < 0) continue;
74343               var nodes = graph.childNodes(entity);
74344
74345               for (var j = 0; j < nodes.length - 1; j++) {
74346                 var a = nodes[j];
74347                 var b = nodes[j + 1];
74348                 var id = [a.id, b.id].sort().join('-');
74349
74350                 if (midpoints[id]) {
74351                   midpoints[id].parents.push(entity);
74352                 } else if (geoVecLength(projection(a.loc), projection(b.loc)) > 40) {
74353                   var point = geoVecInterp(a.loc, b.loc, 0.5);
74354                   var loc = null;
74355
74356                   if (extent.intersects(point)) {
74357                     loc = point;
74358                   } else {
74359                     for (var k = 0; k < 4; k++) {
74360                       point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
74361
74362                       if (point && geoVecLength(projection(a.loc), projection(point)) > 20 && geoVecLength(projection(b.loc), projection(point)) > 20) {
74363                         loc = point;
74364                         break;
74365                       }
74366                     }
74367                   }
74368
74369                   if (loc) {
74370                     midpoints[id] = {
74371                       type: 'midpoint',
74372                       id: id,
74373                       loc: loc,
74374                       edge: [a.id, b.id],
74375                       parents: [entity]
74376                     };
74377                   }
74378                 }
74379               }
74380             }
74381
74382             function midpointFilter(d) {
74383               if (midpoints[d.id]) return true;
74384
74385               for (var i = 0; i < d.parents.length; i++) {
74386                 if (filter(d.parents[i])) {
74387                   return true;
74388                 }
74389               }
74390
74391               return false;
74392             }
74393
74394             var groups = drawLayer.selectAll('.midpoint').filter(midpointFilter).data(Object.values(midpoints), function (d) {
74395               return d.id;
74396             });
74397             groups.exit().remove();
74398             var enter = groups.enter().insert('g', ':first-child').attr('class', 'midpoint');
74399             enter.append('polygon').attr('points', '-6,8 10,0 -6,-8').attr('class', 'shadow');
74400             enter.append('polygon').attr('points', '-3,4 5,0 -3,-4').attr('class', 'fill');
74401             groups = groups.merge(enter).attr('transform', function (d) {
74402               var translate = svgPointTransform(projection);
74403               var a = graph.entity(d.edge[0]);
74404               var b = graph.entity(d.edge[1]);
74405               var angle = geoAngle(a, b, projection) * (180 / Math.PI);
74406               return translate(d) + ' rotate(' + angle + ')';
74407             }).call(svgTagClasses().tags(function (d) {
74408               return d.parents[0].tags;
74409             })); // Propagate data bindings.
74410
74411             groups.select('polygon.shadow');
74412             groups.select('polygon.fill'); // Draw touch targets..
74413
74414             touchLayer.call(drawTargets, graph, Object.values(midpoints), midpointFilter);
74415           }
74416
74417           return drawMidpoints;
74418         }
74419
74420         function svgPoints(projection, context) {
74421           function markerPath(selection, klass) {
74422             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');
74423           }
74424
74425           function sortY(a, b) {
74426             return b.loc[1] - a.loc[1];
74427           } // Avoid exit/enter if we're just moving stuff around.
74428           // The node will get a new version but we only need to run the update selection.
74429
74430
74431           function fastEntityKey(d) {
74432             var mode = context.mode();
74433             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
74434             return isMoving ? d.id : osmEntity.key(d);
74435           }
74436
74437           function drawTargets(selection, graph, entities, filter) {
74438             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
74439             var getTransform = svgPointTransform(projection).geojson;
74440             var activeID = context.activeID();
74441             var data = [];
74442             entities.forEach(function (node) {
74443               if (activeID === node.id) return; // draw no target on the activeID
74444
74445               data.push({
74446                 type: 'Feature',
74447                 id: node.id,
74448                 properties: {
74449                   target: true,
74450                   entity: node
74451                 },
74452                 geometry: node.asGeoJSON()
74453               });
74454             });
74455             var targets = selection.selectAll('.point.target').filter(function (d) {
74456               return filter(d.properties.entity);
74457             }).data(data, function key(d) {
74458               return d.id;
74459             }); // exit
74460
74461             targets.exit().remove(); // enter/update
74462
74463             targets.enter().append('rect').attr('x', -10).attr('y', -26).attr('width', 20).attr('height', 30).merge(targets).attr('class', function (d) {
74464               return 'node point target ' + fillClass + d.id;
74465             }).attr('transform', getTransform);
74466           }
74467
74468           function drawPoints(selection, graph, entities, filter) {
74469             var wireframe = context.surface().classed('fill-wireframe');
74470             var zoom = geoScaleToZoom(projection.scale());
74471             var base = context.history().base(); // Points with a direction will render as vertices at higher zooms..
74472
74473             function renderAsPoint(entity) {
74474               return entity.geometry(graph) === 'point' && !(zoom >= 18 && entity.directions(graph, projection).length);
74475             } // All points will render as vertices in wireframe mode too..
74476
74477
74478             var points = wireframe ? [] : entities.filter(renderAsPoint);
74479             points.sort(sortY);
74480             var drawLayer = selection.selectAll('.layer-osm.points .points-group.points');
74481             var touchLayer = selection.selectAll('.layer-touch.points'); // Draw points..
74482
74483             var groups = drawLayer.selectAll('g.point').filter(filter).data(points, fastEntityKey);
74484             groups.exit().remove();
74485             var enter = groups.enter().append('g').attr('class', function (d) {
74486               return 'node point ' + d.id;
74487             }).order();
74488             enter.append('path').call(markerPath, 'shadow');
74489             enter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
74490             enter.append('path').call(markerPath, 'stroke');
74491             enter.append('use').attr('transform', 'translate(-5, -19)').attr('class', 'icon').attr('width', '11px').attr('height', '11px');
74492             groups = groups.merge(enter).attr('transform', svgPointTransform(projection)).classed('added', function (d) {
74493               return !base.entities[d.id]; // if it doesn't exist in the base graph, it's new
74494             }).classed('moved', function (d) {
74495               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].loc, base.entities[d.id].loc);
74496             }).classed('retagged', function (d) {
74497               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
74498             }).call(svgTagClasses());
74499             groups.select('.shadow'); // propagate bound data
74500
74501             groups.select('.stroke'); // propagate bound data
74502
74503             groups.select('.icon') // propagate bound data
74504             .attr('xlink:href', function (entity) {
74505               var preset = _mainPresetIndex.match(entity, graph);
74506               var picon = preset && preset.icon;
74507
74508               if (!picon) {
74509                 return '';
74510               } else {
74511                 var isMaki = /^maki-/.test(picon);
74512                 return '#' + picon + (isMaki ? '-11' : '');
74513               }
74514             }); // Draw touch targets..
74515
74516             touchLayer.call(drawTargets, graph, points, filter);
74517           }
74518
74519           return drawPoints;
74520         }
74521
74522         function svgTurns(projection, context) {
74523           function icon(turn) {
74524             var u = turn.u ? '-u' : '';
74525             if (turn.no) return '#iD-turn-no' + u;
74526             if (turn.only) return '#iD-turn-only' + u;
74527             return '#iD-turn-yes' + u;
74528           }
74529
74530           function drawTurns(selection, graph, turns) {
74531             function turnTransform(d) {
74532               var pxRadius = 50;
74533               var toWay = graph.entity(d.to.way);
74534               var toPoints = graph.childNodes(toWay).map(function (n) {
74535                 return n.loc;
74536               }).map(projection);
74537               var toLength = geoPathLength(toPoints);
74538               var mid = toLength / 2; // midpoint of destination way
74539
74540               var toNode = graph.entity(d.to.node);
74541               var toVertex = graph.entity(d.to.vertex);
74542               var a = geoAngle(toVertex, toNode, projection);
74543               var o = projection(toVertex.loc);
74544               var r = d.u ? 0 // u-turn: no radius
74545               : !toWay.__via ? pxRadius // leaf way: put marker at pxRadius
74546               : Math.min(mid, pxRadius); // via way: prefer pxRadius, fallback to mid for very short ways
74547
74548               return 'translate(' + (r * Math.cos(a) + o[0]) + ',' + (r * Math.sin(a) + o[1]) + ') ' + 'rotate(' + a * 180 / Math.PI + ')';
74549             }
74550
74551             var drawLayer = selection.selectAll('.layer-osm.points .points-group.turns');
74552             var touchLayer = selection.selectAll('.layer-touch.turns'); // Draw turns..
74553
74554             var groups = drawLayer.selectAll('g.turn').data(turns, function (d) {
74555               return d.key;
74556             }); // exit
74557
74558             groups.exit().remove(); // enter
74559
74560             var groupsEnter = groups.enter().append('g').attr('class', function (d) {
74561               return 'turn ' + d.key;
74562             });
74563             var turnsEnter = groupsEnter.filter(function (d) {
74564               return !d.u;
74565             });
74566             turnsEnter.append('rect').attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
74567             turnsEnter.append('use').attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
74568             var uEnter = groupsEnter.filter(function (d) {
74569               return d.u;
74570             });
74571             uEnter.append('circle').attr('r', '16');
74572             uEnter.append('use').attr('transform', 'translate(-16, -16)').attr('width', '32').attr('height', '32'); // update
74573
74574             groups = groups.merge(groupsEnter).attr('opacity', function (d) {
74575               return d.direct === false ? '0.7' : null;
74576             }).attr('transform', turnTransform);
74577             groups.select('use').attr('xlink:href', icon);
74578             groups.select('rect'); // propagate bound data
74579
74580             groups.select('circle'); // propagate bound data
74581             // Draw touch targets..
74582
74583             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
74584             groups = touchLayer.selectAll('g.turn').data(turns, function (d) {
74585               return d.key;
74586             }); // exit
74587
74588             groups.exit().remove(); // enter
74589
74590             groupsEnter = groups.enter().append('g').attr('class', function (d) {
74591               return 'turn ' + d.key;
74592             });
74593             turnsEnter = groupsEnter.filter(function (d) {
74594               return !d.u;
74595             });
74596             turnsEnter.append('rect').attr('class', 'target ' + fillClass).attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
74597             uEnter = groupsEnter.filter(function (d) {
74598               return d.u;
74599             });
74600             uEnter.append('circle').attr('class', 'target ' + fillClass).attr('r', '16'); // update
74601
74602             groups = groups.merge(groupsEnter).attr('transform', turnTransform);
74603             groups.select('rect'); // propagate bound data
74604
74605             groups.select('circle'); // propagate bound data
74606
74607             return this;
74608           }
74609
74610           return drawTurns;
74611         }
74612
74613         function svgVertices(projection, context) {
74614           var radiuses = {
74615             //       z16-, z17,   z18+,  w/icon
74616             shadow: [6, 7.5, 7.5, 12],
74617             stroke: [2.5, 3.5, 3.5, 8],
74618             fill: [1, 1.5, 1.5, 1.5]
74619           };
74620
74621           var _currHoverTarget;
74622
74623           var _currPersistent = {};
74624           var _currHover = {};
74625           var _prevHover = {};
74626           var _currSelected = {};
74627           var _prevSelected = {};
74628           var _radii = {};
74629
74630           function sortY(a, b) {
74631             return b.loc[1] - a.loc[1];
74632           } // Avoid exit/enter if we're just moving stuff around.
74633           // The node will get a new version but we only need to run the update selection.
74634
74635
74636           function fastEntityKey(d) {
74637             var mode = context.mode();
74638             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
74639             return isMoving ? d.id : osmEntity.key(d);
74640           }
74641
74642           function draw(selection, graph, vertices, sets, filter) {
74643             sets = sets || {
74644               selected: {},
74645               important: {},
74646               hovered: {}
74647             };
74648             var icons = {};
74649             var directions = {};
74650             var wireframe = context.surface().classed('fill-wireframe');
74651             var zoom = geoScaleToZoom(projection.scale());
74652             var z = zoom < 17 ? 0 : zoom < 18 ? 1 : 2;
74653             var activeID = context.activeID();
74654             var base = context.history().base();
74655
74656             function getIcon(d) {
74657               // always check latest entity, as fastEntityKey avoids enter/exit now
74658               var entity = graph.entity(d.id);
74659               if (entity.id in icons) return icons[entity.id];
74660               icons[entity.id] = entity.hasInterestingTags() && _mainPresetIndex.match(entity, graph).icon;
74661               return icons[entity.id];
74662             } // memoize directions results, return false for empty arrays (for use in filter)
74663
74664
74665             function getDirections(entity) {
74666               if (entity.id in directions) return directions[entity.id];
74667               var angles = entity.directions(graph, projection);
74668               directions[entity.id] = angles.length ? angles : false;
74669               return angles;
74670             }
74671
74672             function updateAttributes(selection) {
74673               ['shadow', 'stroke', 'fill'].forEach(function (klass) {
74674                 var rads = radiuses[klass];
74675                 selection.selectAll('.' + klass).each(function (entity) {
74676                   var i = z && getIcon(entity);
74677                   var r = rads[i ? 3 : z]; // slightly increase the size of unconnected endpoints #3775
74678
74679                   if (entity.id !== activeID && entity.isEndpoint(graph) && !entity.isConnected(graph)) {
74680                     r += 1.5;
74681                   }
74682
74683                   if (klass === 'shadow') {
74684                     // remember this value, so we don't need to
74685                     _radii[entity.id] = r; // recompute it when we draw the touch targets
74686                   }
74687
74688                   select(this).attr('r', r).attr('visibility', i && klass === 'fill' ? 'hidden' : null);
74689                 });
74690               });
74691             }
74692
74693             vertices.sort(sortY);
74694             var groups = selection.selectAll('g.vertex').filter(filter).data(vertices, fastEntityKey); // exit
74695
74696             groups.exit().remove(); // enter
74697
74698             var enter = groups.enter().append('g').attr('class', function (d) {
74699               return 'node vertex ' + d.id;
74700             }).order();
74701             enter.append('circle').attr('class', 'shadow');
74702             enter.append('circle').attr('class', 'stroke'); // Vertices with tags get a fill.
74703
74704             enter.filter(function (d) {
74705               return d.hasInterestingTags();
74706             }).append('circle').attr('class', 'fill'); // update
74707
74708             groups = groups.merge(enter).attr('transform', svgPointTransform(projection)).classed('sibling', function (d) {
74709               return d.id in sets.selected;
74710             }).classed('shared', function (d) {
74711               return graph.isShared(d);
74712             }).classed('endpoint', function (d) {
74713               return d.isEndpoint(graph);
74714             }).classed('added', function (d) {
74715               return !base.entities[d.id]; // if it doesn't exist in the base graph, it's new
74716             }).classed('moved', function (d) {
74717               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].loc, base.entities[d.id].loc);
74718             }).classed('retagged', function (d) {
74719               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
74720             }).call(updateAttributes); // Vertices with icons get a `use`.
74721
74722             var iconUse = groups.selectAll('.icon').data(function data(d) {
74723               return zoom >= 17 && getIcon(d) ? [d] : [];
74724             }, fastEntityKey); // exit
74725
74726             iconUse.exit().remove(); // enter
74727
74728             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) {
74729               var picon = getIcon(d);
74730               var isMaki = /^maki-/.test(picon);
74731               return '#' + picon + (isMaki ? '-11' : '');
74732             }); // Vertices with directions get viewfields
74733
74734             var dgroups = groups.selectAll('.viewfieldgroup').data(function data(d) {
74735               return zoom >= 18 && getDirections(d) ? [d] : [];
74736             }, fastEntityKey); // exit
74737
74738             dgroups.exit().remove(); // enter/update
74739
74740             dgroups = dgroups.enter().insert('g', '.shadow').attr('class', 'viewfieldgroup').merge(dgroups);
74741             var viewfields = dgroups.selectAll('.viewfield').data(getDirections, function key(d) {
74742               return osmEntity.key(d);
74743             }); // exit
74744
74745             viewfields.exit().remove(); // enter/update
74746
74747             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) {
74748               return 'rotate(' + d + ')';
74749             });
74750           }
74751
74752           function drawTargets(selection, graph, entities, filter) {
74753             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
74754             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
74755             var getTransform = svgPointTransform(projection).geojson;
74756             var activeID = context.activeID();
74757             var data = {
74758               targets: [],
74759               nopes: []
74760             };
74761             entities.forEach(function (node) {
74762               if (activeID === node.id) return; // draw no target on the activeID
74763
74764               var vertexType = svgPassiveVertex(node, graph, activeID);
74765
74766               if (vertexType !== 0) {
74767                 // passive or adjacent - allow to connect
74768                 data.targets.push({
74769                   type: 'Feature',
74770                   id: node.id,
74771                   properties: {
74772                     target: true,
74773                     entity: node
74774                   },
74775                   geometry: node.asGeoJSON()
74776                 });
74777               } else {
74778                 data.nopes.push({
74779                   type: 'Feature',
74780                   id: node.id + '-nope',
74781                   properties: {
74782                     nope: true,
74783                     target: true,
74784                     entity: node
74785                   },
74786                   geometry: node.asGeoJSON()
74787                 });
74788               }
74789             }); // Targets allow hover and vertex snapping
74790
74791             var targets = selection.selectAll('.vertex.target-allowed').filter(function (d) {
74792               return filter(d.properties.entity);
74793             }).data(data.targets, function key(d) {
74794               return d.id;
74795             }); // exit
74796
74797             targets.exit().remove(); // enter/update
74798
74799             targets.enter().append('circle').attr('r', function (d) {
74800               return _radii[d.id] || radiuses.shadow[3];
74801             }).merge(targets).attr('class', function (d) {
74802               return 'node vertex target target-allowed ' + targetClass + d.id;
74803             }).attr('transform', getTransform); // NOPE
74804
74805             var nopes = selection.selectAll('.vertex.target-nope').filter(function (d) {
74806               return filter(d.properties.entity);
74807             }).data(data.nopes, function key(d) {
74808               return d.id;
74809             }); // exit
74810
74811             nopes.exit().remove(); // enter/update
74812
74813             nopes.enter().append('circle').attr('r', function (d) {
74814               return _radii[d.properties.entity.id] || radiuses.shadow[3];
74815             }).merge(nopes).attr('class', function (d) {
74816               return 'node vertex target target-nope ' + nopeClass + d.id;
74817             }).attr('transform', getTransform);
74818           } // Points can also render as vertices:
74819           // 1. in wireframe mode or
74820           // 2. at higher zooms if they have a direction
74821
74822
74823           function renderAsVertex(entity, graph, wireframe, zoom) {
74824             var geometry = entity.geometry(graph);
74825             return geometry === 'vertex' || geometry === 'point' && (wireframe || zoom >= 18 && entity.directions(graph, projection).length);
74826           }
74827
74828           function isEditedNode(node, base, head) {
74829             var baseNode = base.entities[node.id];
74830             var headNode = head.entities[node.id];
74831             return !headNode || !baseNode || !fastDeepEqual(headNode.tags, baseNode.tags) || !fastDeepEqual(headNode.loc, baseNode.loc);
74832           }
74833
74834           function getSiblingAndChildVertices(ids, graph, wireframe, zoom) {
74835             var results = {};
74836             var seenIds = {};
74837
74838             function addChildVertices(entity) {
74839               // avoid redundant work and infinite recursion of circular relations
74840               if (seenIds[entity.id]) return;
74841               seenIds[entity.id] = true;
74842               var geometry = entity.geometry(graph);
74843
74844               if (!context.features().isHiddenFeature(entity, graph, geometry)) {
74845                 var i;
74846
74847                 if (entity.type === 'way') {
74848                   for (i = 0; i < entity.nodes.length; i++) {
74849                     var child = graph.hasEntity(entity.nodes[i]);
74850
74851                     if (child) {
74852                       addChildVertices(child);
74853                     }
74854                   }
74855                 } else if (entity.type === 'relation') {
74856                   for (i = 0; i < entity.members.length; i++) {
74857                     var member = graph.hasEntity(entity.members[i].id);
74858
74859                     if (member) {
74860                       addChildVertices(member);
74861                     }
74862                   }
74863                 } else if (renderAsVertex(entity, graph, wireframe, zoom)) {
74864                   results[entity.id] = entity;
74865                 }
74866               }
74867             }
74868
74869             ids.forEach(function (id) {
74870               var entity = graph.hasEntity(id);
74871               if (!entity) return;
74872
74873               if (entity.type === 'node') {
74874                 if (renderAsVertex(entity, graph, wireframe, zoom)) {
74875                   results[entity.id] = entity;
74876                   graph.parentWays(entity).forEach(function (entity) {
74877                     addChildVertices(entity);
74878                   });
74879                 }
74880               } else {
74881                 // way, relation
74882                 addChildVertices(entity);
74883               }
74884             });
74885             return results;
74886           }
74887
74888           function drawVertices(selection, graph, entities, filter, extent, fullRedraw) {
74889             var wireframe = context.surface().classed('fill-wireframe');
74890             var visualDiff = context.surface().classed('highlight-edited');
74891             var zoom = geoScaleToZoom(projection.scale());
74892             var mode = context.mode();
74893             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
74894             var base = context.history().base();
74895             var drawLayer = selection.selectAll('.layer-osm.points .points-group.vertices');
74896             var touchLayer = selection.selectAll('.layer-touch.points');
74897
74898             if (fullRedraw) {
74899               _currPersistent = {};
74900               _radii = {};
74901             } // Collect important vertices from the `entities` list..
74902             // (during a partial redraw, it will not contain everything)
74903
74904
74905             for (var i = 0; i < entities.length; i++) {
74906               var entity = entities[i];
74907               var geometry = entity.geometry(graph);
74908               var keep = false; // a point that looks like a vertex..
74909
74910               if (geometry === 'point' && renderAsVertex(entity, graph, wireframe, zoom)) {
74911                 _currPersistent[entity.id] = entity;
74912                 keep = true; // a vertex of some importance..
74913               } else if (geometry === 'vertex' && (entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || visualDiff && isEditedNode(entity, base, graph))) {
74914                 _currPersistent[entity.id] = entity;
74915                 keep = true;
74916               } // whatever this is, it's not a persistent vertex..
74917
74918
74919               if (!keep && !fullRedraw) {
74920                 delete _currPersistent[entity.id];
74921               }
74922             } // 3 sets of vertices to consider:
74923
74924
74925             var sets = {
74926               persistent: _currPersistent,
74927               // persistent = important vertices (render always)
74928               selected: _currSelected,
74929               // selected + siblings of selected (render always)
74930               hovered: _currHover // hovered + siblings of hovered (render only in draw modes)
74931
74932             };
74933             var all = Object.assign({}, isMoving ? _currHover : {}, _currSelected, _currPersistent); // Draw the vertices..
74934             // The filter function controls the scope of what objects d3 will touch (exit/enter/update)
74935             // Adjust the filter function to expand the scope beyond whatever entities were passed in.
74936
74937             var filterRendered = function filterRendered(d) {
74938               return d.id in _currPersistent || d.id in _currSelected || d.id in _currHover || filter(d);
74939             };
74940
74941             drawLayer.call(draw, graph, currentVisible(all), sets, filterRendered); // Draw touch targets..
74942             // When drawing, render all targets (not just those affected by a partial redraw)
74943
74944             var filterTouch = function filterTouch(d) {
74945               return isMoving ? true : filterRendered(d);
74946             };
74947
74948             touchLayer.call(drawTargets, graph, currentVisible(all), filterTouch);
74949
74950             function currentVisible(which) {
74951               return Object.keys(which).map(graph.hasEntity, graph) // the current version of this entity
74952               .filter(function (entity) {
74953                 return entity && entity.intersects(extent, graph);
74954               });
74955             }
74956           } // partial redraw - only update the selected items..
74957
74958
74959           drawVertices.drawSelected = function (selection, graph, extent) {
74960             var wireframe = context.surface().classed('fill-wireframe');
74961             var zoom = geoScaleToZoom(projection.scale());
74962             _prevSelected = _currSelected || {};
74963
74964             if (context.map().isInWideSelection()) {
74965               _currSelected = {};
74966               context.selectedIDs().forEach(function (id) {
74967                 var entity = graph.hasEntity(id);
74968                 if (!entity) return;
74969
74970                 if (entity.type === 'node') {
74971                   if (renderAsVertex(entity, graph, wireframe, zoom)) {
74972                     _currSelected[entity.id] = entity;
74973                   }
74974                 }
74975               });
74976             } else {
74977               _currSelected = getSiblingAndChildVertices(context.selectedIDs(), graph, wireframe, zoom);
74978             } // note that drawVertices will add `_currSelected` automatically if needed..
74979
74980
74981             var filter = function filter(d) {
74982               return d.id in _prevSelected;
74983             };
74984
74985             drawVertices(selection, graph, Object.values(_prevSelected), filter, extent, false);
74986           }; // partial redraw - only update the hovered items..
74987
74988
74989           drawVertices.drawHover = function (selection, graph, target, extent) {
74990             if (target === _currHoverTarget) return; // continue only if something changed
74991
74992             var wireframe = context.surface().classed('fill-wireframe');
74993             var zoom = geoScaleToZoom(projection.scale());
74994             _prevHover = _currHover || {};
74995             _currHoverTarget = target;
74996             var entity = target && target.properties && target.properties.entity;
74997
74998             if (entity) {
74999               _currHover = getSiblingAndChildVertices([entity.id], graph, wireframe, zoom);
75000             } else {
75001               _currHover = {};
75002             } // note that drawVertices will add `_currHover` automatically if needed..
75003
75004
75005             var filter = function filter(d) {
75006               return d.id in _prevHover;
75007             };
75008
75009             drawVertices(selection, graph, Object.values(_prevHover), filter, extent, false);
75010           };
75011
75012           return drawVertices;
75013         }
75014
75015         function utilBindOnce(target, type, listener, capture) {
75016           var typeOnce = type + '.once';
75017
75018           function one() {
75019             target.on(typeOnce, null);
75020             listener.apply(this, arguments);
75021           }
75022
75023           target.on(typeOnce, one, capture);
75024           return this;
75025         }
75026
75027         function defaultFilter$2(d3_event) {
75028           return !d3_event.ctrlKey && !d3_event.button;
75029         }
75030
75031         function defaultExtent$1() {
75032           var e = this;
75033
75034           if (e instanceof SVGElement) {
75035             e = e.ownerSVGElement || e;
75036
75037             if (e.hasAttribute('viewBox')) {
75038               e = e.viewBox.baseVal;
75039               return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
75040             }
75041
75042             return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
75043           }
75044
75045           return [[0, 0], [e.clientWidth, e.clientHeight]];
75046         }
75047
75048         function defaultWheelDelta$1(d3_event) {
75049           return -d3_event.deltaY * (d3_event.deltaMode === 1 ? 0.05 : d3_event.deltaMode ? 1 : 0.002);
75050         }
75051
75052         function defaultConstrain$1(transform, extent, translateExtent) {
75053           var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0],
75054               dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0],
75055               dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1],
75056               dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];
75057           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));
75058         }
75059
75060         function utilZoomPan() {
75061           var filter = defaultFilter$2,
75062               extent = defaultExtent$1,
75063               constrain = defaultConstrain$1,
75064               wheelDelta = defaultWheelDelta$1,
75065               scaleExtent = [0, Infinity],
75066               translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],
75067               interpolate = interpolateZoom,
75068               dispatch$1 = dispatch('start', 'zoom', 'end'),
75069               _wheelDelay = 150,
75070               _transform = identity$2,
75071               _activeGesture;
75072
75073           function zoom(selection) {
75074             selection.on('pointerdown.zoom', pointerdown).on('wheel.zoom', wheeled).style('touch-action', 'none').style('-webkit-tap-highlight-color', 'rgba(0,0,0,0)');
75075             select(window).on('pointermove.zoompan', pointermove).on('pointerup.zoompan pointercancel.zoompan', pointerup);
75076           }
75077
75078           zoom.transform = function (collection, transform, point) {
75079             var selection = collection.selection ? collection.selection() : collection;
75080
75081             if (collection !== selection) {
75082               schedule(collection, transform, point);
75083             } else {
75084               selection.interrupt().each(function () {
75085                 gesture(this, arguments).start(null).zoom(null, null, typeof transform === 'function' ? transform.apply(this, arguments) : transform).end(null);
75086               });
75087             }
75088           };
75089
75090           zoom.scaleBy = function (selection, k, p) {
75091             zoom.scaleTo(selection, function () {
75092               var k0 = _transform.k,
75093                   k1 = typeof k === 'function' ? k.apply(this, arguments) : k;
75094               return k0 * k1;
75095             }, p);
75096           };
75097
75098           zoom.scaleTo = function (selection, k, p) {
75099             zoom.transform(selection, function () {
75100               var e = extent.apply(this, arguments),
75101                   t0 = _transform,
75102                   p0 = !p ? centroid(e) : typeof p === 'function' ? p.apply(this, arguments) : p,
75103                   p1 = t0.invert(p0),
75104                   k1 = typeof k === 'function' ? k.apply(this, arguments) : k;
75105               return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
75106             }, p);
75107           };
75108
75109           zoom.translateBy = function (selection, x, y) {
75110             zoom.transform(selection, function () {
75111               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);
75112             });
75113           };
75114
75115           zoom.translateTo = function (selection, x, y, p) {
75116             zoom.transform(selection, function () {
75117               var e = extent.apply(this, arguments),
75118                   t = _transform,
75119                   p0 = !p ? centroid(e) : typeof p === 'function' ? p.apply(this, arguments) : p;
75120               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);
75121             }, p);
75122           };
75123
75124           function scale(transform, k) {
75125             k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
75126             return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
75127           }
75128
75129           function translate(transform, p0, p1) {
75130             var x = p0[0] - p1[0] * transform.k,
75131                 y = p0[1] - p1[1] * transform.k;
75132             return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
75133           }
75134
75135           function centroid(extent) {
75136             return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
75137           }
75138
75139           function schedule(transition, transform, point) {
75140             transition.on('start.zoom', function () {
75141               gesture(this, arguments).start(null);
75142             }).on('interrupt.zoom end.zoom', function () {
75143               gesture(this, arguments).end(null);
75144             }).tween('zoom', function () {
75145               var that = this,
75146                   args = arguments,
75147                   g = gesture(that, args),
75148                   e = extent.apply(that, args),
75149                   p = !point ? centroid(e) : typeof point === 'function' ? point.apply(that, args) : point,
75150                   w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
75151                   a = _transform,
75152                   b = typeof transform === 'function' ? transform.apply(that, args) : transform,
75153                   i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
75154               return function (t) {
75155                 if (t === 1) t = b; // Avoid rounding error on end.
75156                 else {
75157                     var l = i(t),
75158                         k = w / l[2];
75159                     t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
75160                   }
75161                 g.zoom(null, null, t);
75162               };
75163             });
75164           }
75165
75166           function gesture(that, args, clean) {
75167             return !clean && _activeGesture || new Gesture(that, args);
75168           }
75169
75170           function Gesture(that, args) {
75171             this.that = that;
75172             this.args = args;
75173             this.active = 0;
75174             this.extent = extent.apply(that, args);
75175           }
75176
75177           Gesture.prototype = {
75178             start: function start(d3_event) {
75179               if (++this.active === 1) {
75180                 _activeGesture = this;
75181                 dispatch$1.call('start', this, d3_event);
75182               }
75183
75184               return this;
75185             },
75186             zoom: function zoom(d3_event, key, transform) {
75187               if (this.mouse && key !== 'mouse') this.mouse[1] = transform.invert(this.mouse[0]);
75188               if (this.pointer0 && key !== 'touch') this.pointer0[1] = transform.invert(this.pointer0[0]);
75189               if (this.pointer1 && key !== 'touch') this.pointer1[1] = transform.invert(this.pointer1[0]);
75190               _transform = transform;
75191               dispatch$1.call('zoom', this, d3_event, key, transform);
75192               return this;
75193             },
75194             end: function end(d3_event) {
75195               if (--this.active === 0) {
75196                 _activeGesture = null;
75197                 dispatch$1.call('end', this, d3_event);
75198               }
75199
75200               return this;
75201             }
75202           };
75203
75204           function wheeled(d3_event) {
75205             if (!filter.apply(this, arguments)) return;
75206             var g = gesture(this, arguments),
75207                 t = _transform,
75208                 k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),
75209                 p = utilFastMouse(this)(d3_event); // If the mouse is in the same location as before, reuse it.
75210             // If there were recent wheel events, reset the wheel idle timeout.
75211
75212             if (g.wheel) {
75213               if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
75214                 g.mouse[1] = t.invert(g.mouse[0] = p);
75215               }
75216
75217               clearTimeout(g.wheel); // Otherwise, capture the mouse point and location at the start.
75218             } else {
75219               g.mouse = [p, t.invert(p)];
75220               interrupt(this);
75221               g.start(d3_event);
75222             }
75223
75224             d3_event.preventDefault();
75225             d3_event.stopImmediatePropagation();
75226             g.wheel = setTimeout(wheelidled, _wheelDelay);
75227             g.zoom(d3_event, 'mouse', constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
75228
75229             function wheelidled() {
75230               g.wheel = null;
75231               g.end(d3_event);
75232             }
75233           }
75234
75235           var _downPointerIDs = new Set();
75236
75237           var _pointerLocGetter;
75238
75239           function pointerdown(d3_event) {
75240             _downPointerIDs.add(d3_event.pointerId);
75241
75242             if (!filter.apply(this, arguments)) return;
75243             var g = gesture(this, arguments, _downPointerIDs.size === 1);
75244             var started;
75245             d3_event.stopImmediatePropagation();
75246             _pointerLocGetter = utilFastMouse(this);
75247
75248             var loc = _pointerLocGetter(d3_event);
75249
75250             var p = [loc, _transform.invert(loc), d3_event.pointerId];
75251
75252             if (!g.pointer0) {
75253               g.pointer0 = p;
75254               started = true;
75255             } else if (!g.pointer1 && g.pointer0[2] !== p[2]) {
75256               g.pointer1 = p;
75257             }
75258
75259             if (started) {
75260               interrupt(this);
75261               g.start(d3_event);
75262             }
75263           }
75264
75265           function pointermove(d3_event) {
75266             if (!_downPointerIDs.has(d3_event.pointerId)) return;
75267             if (!_activeGesture || !_pointerLocGetter) return;
75268             var g = gesture(this, arguments);
75269             var isPointer0 = g.pointer0 && g.pointer0[2] === d3_event.pointerId;
75270             var isPointer1 = !isPointer0 && g.pointer1 && g.pointer1[2] === d3_event.pointerId;
75271
75272             if ((isPointer0 || isPointer1) && 'buttons' in d3_event && !d3_event.buttons) {
75273               // The pointer went up without ending the gesture somehow, e.g.
75274               // a down mouse was moved off the map and released. End it here.
75275               if (g.pointer0) _downPointerIDs["delete"](g.pointer0[2]);
75276               if (g.pointer1) _downPointerIDs["delete"](g.pointer1[2]);
75277               g.end(d3_event);
75278               return;
75279             }
75280
75281             d3_event.preventDefault();
75282             d3_event.stopImmediatePropagation();
75283
75284             var loc = _pointerLocGetter(d3_event);
75285
75286             var t, p, l;
75287             if (isPointer0) g.pointer0[0] = loc;else if (isPointer1) g.pointer1[0] = loc;
75288             t = _transform;
75289
75290             if (g.pointer1) {
75291               var p0 = g.pointer0[0],
75292                   l0 = g.pointer0[1],
75293                   p1 = g.pointer1[0],
75294                   l1 = g.pointer1[1],
75295                   dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
75296                   dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
75297               t = scale(t, Math.sqrt(dp / dl));
75298               p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
75299               l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
75300             } else if (g.pointer0) {
75301               p = g.pointer0[0];
75302               l = g.pointer0[1];
75303             } else return;
75304
75305             g.zoom(d3_event, 'touch', constrain(translate(t, p, l), g.extent, translateExtent));
75306           }
75307
75308           function pointerup(d3_event) {
75309             if (!_downPointerIDs.has(d3_event.pointerId)) return;
75310
75311             _downPointerIDs["delete"](d3_event.pointerId);
75312
75313             if (!_activeGesture) return;
75314             var g = gesture(this, arguments);
75315             d3_event.stopImmediatePropagation();
75316             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;
75317
75318             if (g.pointer1 && !g.pointer0) {
75319               g.pointer0 = g.pointer1;
75320               delete g.pointer1;
75321             }
75322
75323             if (g.pointer0) g.pointer0[1] = _transform.invert(g.pointer0[0]);else {
75324               g.end(d3_event);
75325             }
75326           }
75327
75328           zoom.wheelDelta = function (_) {
75329             return arguments.length ? (wheelDelta = utilFunctor(+_), zoom) : wheelDelta;
75330           };
75331
75332           zoom.filter = function (_) {
75333             return arguments.length ? (filter = utilFunctor(!!_), zoom) : filter;
75334           };
75335
75336           zoom.extent = function (_) {
75337             return arguments.length ? (extent = utilFunctor([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
75338           };
75339
75340           zoom.scaleExtent = function (_) {
75341             return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
75342           };
75343
75344           zoom.translateExtent = function (_) {
75345             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]]];
75346           };
75347
75348           zoom.constrain = function (_) {
75349             return arguments.length ? (constrain = _, zoom) : constrain;
75350           };
75351
75352           zoom.interpolate = function (_) {
75353             return arguments.length ? (interpolate = _, zoom) : interpolate;
75354           };
75355
75356           zoom._transform = function (_) {
75357             return arguments.length ? (_transform = _, zoom) : _transform;
75358           };
75359
75360           return utilRebind(zoom, dispatch$1, 'on');
75361         }
75362
75363         // if pointer events are supported. Falls back to default `dblclick` event.
75364
75365         function utilDoubleUp() {
75366           var dispatch$1 = dispatch('doubleUp');
75367           var _maxTimespan = 500; // milliseconds
75368
75369           var _maxDistance = 20; // web pixels; be somewhat generous to account for touch devices
75370
75371           var _pointer; // object representing the pointer that could trigger double up
75372
75373
75374           function pointerIsValidFor(loc) {
75375             // second pointerup must occur within a small timeframe after the first pointerdown
75376             return new Date().getTime() - _pointer.startTime <= _maxTimespan && // all pointer events must occur within a small distance of the first pointerdown
75377             geoVecLength(_pointer.startLoc, loc) <= _maxDistance;
75378           }
75379
75380           function pointerdown(d3_event) {
75381             // ignore right-click
75382             if (d3_event.ctrlKey || d3_event.button === 2) return;
75383             var loc = [d3_event.clientX, d3_event.clientY]; // Don't rely on pointerId here since it can change between pointerdown
75384             // events on touch devices
75385
75386             if (_pointer && !pointerIsValidFor(loc)) {
75387               // if this pointer is no longer valid, clear it so another can be started
75388               _pointer = undefined;
75389             }
75390
75391             if (!_pointer) {
75392               _pointer = {
75393                 startLoc: loc,
75394                 startTime: new Date().getTime(),
75395                 upCount: 0,
75396                 pointerId: d3_event.pointerId
75397               };
75398             } else {
75399               // double down
75400               _pointer.pointerId = d3_event.pointerId;
75401             }
75402           }
75403
75404           function pointerup(d3_event) {
75405             // ignore right-click
75406             if (d3_event.ctrlKey || d3_event.button === 2) return;
75407             if (!_pointer || _pointer.pointerId !== d3_event.pointerId) return;
75408             _pointer.upCount += 1;
75409
75410             if (_pointer.upCount === 2) {
75411               // double up!
75412               var loc = [d3_event.clientX, d3_event.clientY];
75413
75414               if (pointerIsValidFor(loc)) {
75415                 var locInThis = utilFastMouse(this)(d3_event);
75416                 dispatch$1.call('doubleUp', this, d3_event, locInThis);
75417               } // clear the pointer info in any case
75418
75419
75420               _pointer = undefined;
75421             }
75422           }
75423
75424           function doubleUp(selection) {
75425             if ('PointerEvent' in window) {
75426               // dblclick isn't well supported on touch devices so manually use
75427               // pointer events if they're available
75428               selection.on('pointerdown.doubleUp', pointerdown).on('pointerup.doubleUp', pointerup);
75429             } else {
75430               // fallback to dblclick
75431               selection.on('dblclick.doubleUp', function (d3_event) {
75432                 dispatch$1.call('doubleUp', this, d3_event, utilFastMouse(this)(d3_event));
75433               });
75434             }
75435           }
75436
75437           doubleUp.off = function (selection) {
75438             selection.on('pointerdown.doubleUp', null).on('pointerup.doubleUp', null).on('dblclick.doubleUp', null);
75439           };
75440
75441           return utilRebind(doubleUp, dispatch$1, 'on');
75442         }
75443
75444         var TILESIZE = 256;
75445         var minZoom = 2;
75446         var maxZoom = 24;
75447         var kMin = geoZoomToScale(minZoom, TILESIZE);
75448         var kMax = geoZoomToScale(maxZoom, TILESIZE);
75449
75450         function clamp(num, min, max) {
75451           return Math.max(min, Math.min(num, max));
75452         }
75453
75454         function rendererMap(context) {
75455           var dispatch$1 = dispatch('move', 'drawn', 'crossEditableZoom', 'hitMinZoom', 'changeHighlighting', 'changeAreaFill');
75456           var projection = context.projection;
75457           var curtainProjection = context.curtainProjection;
75458           var drawLayers;
75459           var drawPoints;
75460           var drawVertices;
75461           var drawLines;
75462           var drawAreas;
75463           var drawMidpoints;
75464           var drawLabels;
75465
75466           var _selection = select(null);
75467
75468           var supersurface = select(null);
75469           var wrapper = select(null);
75470           var surface = select(null);
75471           var _dimensions = [1, 1];
75472           var _dblClickZoomEnabled = true;
75473           var _redrawEnabled = true;
75474
75475           var _gestureTransformStart;
75476
75477           var _transformStart = projection.transform();
75478
75479           var _transformLast;
75480
75481           var _isTransformed = false;
75482           var _minzoom = 0;
75483
75484           var _getMouseCoords;
75485
75486           var _lastPointerEvent;
75487
75488           var _lastWithinEditableZoom; // whether a pointerdown event started the zoom
75489
75490
75491           var _pointerDown = false; // use pointer events on supported platforms; fallback to mouse events
75492
75493           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // use pointer event interaction if supported; fallback to touch/mouse events in d3-zoom
75494
75495
75496           var _zoomerPannerFunction = 'PointerEvent' in window ? utilZoomPan : d3_zoom;
75497
75498           var _zoomerPanner = _zoomerPannerFunction().scaleExtent([kMin, kMax]).interpolate(interpolate).filter(zoomEventFilter).on('zoom.map', zoomPan).on('start.map', function (d3_event) {
75499             _pointerDown = d3_event && (d3_event.type === 'pointerdown' || d3_event.sourceEvent && d3_event.sourceEvent.type === 'pointerdown');
75500           }).on('end.map', function () {
75501             _pointerDown = false;
75502           });
75503
75504           var _doubleUpHandler = utilDoubleUp();
75505
75506           var scheduleRedraw = throttle(redraw, 750); // var isRedrawScheduled = false;
75507           // var pendingRedrawCall;
75508           // function scheduleRedraw() {
75509           //     // Only schedule the redraw if one has not already been set.
75510           //     if (isRedrawScheduled) return;
75511           //     isRedrawScheduled = true;
75512           //     var that = this;
75513           //     var args = arguments;
75514           //     pendingRedrawCall = window.requestIdleCallback(function () {
75515           //         // Reset the boolean so future redraws can be set.
75516           //         isRedrawScheduled = false;
75517           //         redraw.apply(that, args);
75518           //     }, { timeout: 1400 });
75519           // }
75520
75521
75522           function cancelPendingRedraw() {
75523             scheduleRedraw.cancel(); // isRedrawScheduled = false;
75524             // window.cancelIdleCallback(pendingRedrawCall);
75525           }
75526
75527           function map(selection) {
75528             _selection = selection;
75529             context.on('change.map', immediateRedraw);
75530             var osm = context.connection();
75531
75532             if (osm) {
75533               osm.on('change.map', immediateRedraw);
75534             }
75535
75536             function didUndoOrRedo(targetTransform) {
75537               var mode = context.mode().id;
75538               if (mode !== 'browse' && mode !== 'select') return;
75539
75540               if (targetTransform) {
75541                 map.transformEase(targetTransform);
75542               }
75543             }
75544
75545             context.history().on('merge.map', function () {
75546               scheduleRedraw();
75547             }).on('change.map', immediateRedraw).on('undone.map', function (stack, fromStack) {
75548               didUndoOrRedo(fromStack.transform);
75549             }).on('redone.map', function (stack) {
75550               didUndoOrRedo(stack.transform);
75551             });
75552             context.background().on('change.map', immediateRedraw);
75553             context.features().on('redraw.map', immediateRedraw);
75554             drawLayers.on('change.map', function () {
75555               context.background().updateImagery();
75556               immediateRedraw();
75557             });
75558             selection.on('wheel.map mousewheel.map', function (d3_event) {
75559               // disable swipe-to-navigate browser pages on trackpad/magic mouse – #5552
75560               d3_event.preventDefault();
75561             }).call(_zoomerPanner).call(_zoomerPanner.transform, projection.transform()).on('dblclick.zoom', null); // override d3-zoom dblclick handling
75562
75563             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
75564             // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
75565
75566             wrapper = supersurface.append('div').attr('class', 'layer layer-data');
75567             map.surface = surface = wrapper.call(drawLayers).selectAll('.surface');
75568             surface.call(drawLabels.observe).call(_doubleUpHandler).on(_pointerPrefix + 'down.zoom', function (d3_event) {
75569               _lastPointerEvent = d3_event;
75570
75571               if (d3_event.button === 2) {
75572                 d3_event.stopPropagation();
75573               }
75574             }, true).on(_pointerPrefix + 'up.zoom', function (d3_event) {
75575               _lastPointerEvent = d3_event;
75576
75577               if (resetTransform()) {
75578                 immediateRedraw();
75579               }
75580             }).on(_pointerPrefix + 'move.map', function (d3_event) {
75581               _lastPointerEvent = d3_event;
75582             }).on(_pointerPrefix + 'over.vertices', function (d3_event) {
75583               if (map.editableDataEnabled() && !_isTransformed) {
75584                 var hover = d3_event.target.__data__;
75585                 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
75586                 dispatch$1.call('drawn', this, {
75587                   full: false
75588                 });
75589               }
75590             }).on(_pointerPrefix + 'out.vertices', function (d3_event) {
75591               if (map.editableDataEnabled() && !_isTransformed) {
75592                 var hover = d3_event.relatedTarget && d3_event.relatedTarget.__data__;
75593                 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
75594                 dispatch$1.call('drawn', this, {
75595                   full: false
75596                 });
75597               }
75598             });
75599             var detected = utilDetect(); // only WebKit supports gesture events
75600
75601             if ('GestureEvent' in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
75602             // but we only need to do this on desktop Safari anyway. – #7694
75603             !detected.isMobileWebKit) {
75604               // Desktop Safari sends gesture events for multitouch trackpad pinches.
75605               // We can listen for these and translate them into map zooms.
75606               surface.on('gesturestart.surface', function (d3_event) {
75607                 d3_event.preventDefault();
75608                 _gestureTransformStart = projection.transform();
75609               }).on('gesturechange.surface', gestureChange);
75610             } // must call after surface init
75611
75612
75613             updateAreaFill();
75614
75615             _doubleUpHandler.on('doubleUp.map', function (d3_event, p0) {
75616               if (!_dblClickZoomEnabled) return; // don't zoom if targeting something other than the map itself
75617
75618               if (_typeof(d3_event.target.__data__) === 'object' && // or area fills
75619               !select(d3_event.target).classed('fill')) return;
75620               var zoomOut = d3_event.shiftKey;
75621               var t = projection.transform();
75622               var p1 = t.invert(p0);
75623               t = t.scale(zoomOut ? 0.5 : 2);
75624               t.x = p0[0] - p1[0] * t.k;
75625               t.y = p0[1] - p1[1] * t.k;
75626               map.transformEase(t);
75627             });
75628
75629             context.on('enter.map', function () {
75630               if (!map.editableDataEnabled(true
75631               /* skip zoom check */
75632               )) return; // redraw immediately any objects affected by a change in selectedIDs.
75633
75634               var graph = context.graph();
75635               var selectedAndParents = {};
75636               context.selectedIDs().forEach(function (id) {
75637                 var entity = graph.hasEntity(id);
75638
75639                 if (entity) {
75640                   selectedAndParents[entity.id] = entity;
75641
75642                   if (entity.type === 'node') {
75643                     graph.parentWays(entity).forEach(function (parent) {
75644                       selectedAndParents[parent.id] = parent;
75645                     });
75646                   }
75647                 }
75648               });
75649               var data = Object.values(selectedAndParents);
75650
75651               var filter = function filter(d) {
75652                 return d.id in selectedAndParents;
75653               };
75654
75655               data = context.features().filter(data, graph);
75656               surface.call(drawVertices.drawSelected, graph, map.extent()).call(drawLines, graph, data, filter).call(drawAreas, graph, data, filter).call(drawMidpoints, graph, data, filter, map.trimmedExtent());
75657               dispatch$1.call('drawn', this, {
75658                 full: false
75659               }); // redraw everything else later
75660
75661               scheduleRedraw();
75662             });
75663             map.dimensions(utilGetDimensions(selection));
75664           }
75665
75666           function zoomEventFilter(d3_event) {
75667             // Fix for #2151, (see also d3/d3-zoom#60, d3/d3-brush#18)
75668             // Intercept `mousedown` and check if there is an orphaned zoom gesture.
75669             // This can happen if a previous `mousedown` occurred without a `mouseup`.
75670             // If we detect this, dispatch `mouseup` to complete the orphaned gesture,
75671             // so that d3-zoom won't stop propagation of new `mousedown` events.
75672             if (d3_event.type === 'mousedown') {
75673               var hasOrphan = false;
75674               var listeners = window.__on;
75675
75676               for (var i = 0; i < listeners.length; i++) {
75677                 var listener = listeners[i];
75678
75679                 if (listener.name === 'zoom' && listener.type === 'mouseup') {
75680                   hasOrphan = true;
75681                   break;
75682                 }
75683               }
75684
75685               if (hasOrphan) {
75686                 var event = window.CustomEvent;
75687
75688                 if (event) {
75689                   event = new event('mouseup');
75690                 } else {
75691                   event = window.document.createEvent('Event');
75692                   event.initEvent('mouseup', false, false);
75693                 } // Event needs to be dispatched with an event.view property.
75694
75695
75696                 event.view = window;
75697                 window.dispatchEvent(event);
75698               }
75699             }
75700
75701             return d3_event.button !== 2; // ignore right clicks
75702           }
75703
75704           function pxCenter() {
75705             return [_dimensions[0] / 2, _dimensions[1] / 2];
75706           }
75707
75708           function drawEditable(difference, extent) {
75709             var mode = context.mode();
75710             var graph = context.graph();
75711             var features = context.features();
75712             var all = context.history().intersects(map.extent());
75713             var fullRedraw = false;
75714             var data;
75715             var set;
75716             var filter;
75717             var applyFeatureLayerFilters = true;
75718
75719             if (map.isInWideSelection()) {
75720               data = [];
75721               utilEntityAndDeepMemberIDs(mode.selectedIDs(), context.graph()).forEach(function (id) {
75722                 var entity = context.hasEntity(id);
75723                 if (entity) data.push(entity);
75724               });
75725               fullRedraw = true;
75726               filter = utilFunctor(true); // selected features should always be visible, so we can skip filtering
75727
75728               applyFeatureLayerFilters = false;
75729             } else if (difference) {
75730               var complete = difference.complete(map.extent());
75731               data = Object.values(complete).filter(Boolean);
75732               set = new Set(Object.keys(complete));
75733
75734               filter = function filter(d) {
75735                 return set.has(d.id);
75736               };
75737
75738               features.clear(data);
75739             } else {
75740               // force a full redraw if gatherStats detects that a feature
75741               // should be auto-hidden (e.g. points or buildings)..
75742               if (features.gatherStats(all, graph, _dimensions)) {
75743                 extent = undefined;
75744               }
75745
75746               if (extent) {
75747                 data = context.history().intersects(map.extent().intersection(extent));
75748                 set = new Set(data.map(function (entity) {
75749                   return entity.id;
75750                 }));
75751
75752                 filter = function filter(d) {
75753                   return set.has(d.id);
75754                 };
75755               } else {
75756                 data = all;
75757                 fullRedraw = true;
75758                 filter = utilFunctor(true);
75759               }
75760             }
75761
75762             if (applyFeatureLayerFilters) {
75763               data = features.filter(data, graph);
75764             } else {
75765               context.features().resetStats();
75766             }
75767
75768             if (mode && mode.id === 'select') {
75769               // update selected vertices - the user might have just double-clicked a way,
75770               // creating a new vertex, triggering a partial redraw without a mode change
75771               surface.call(drawVertices.drawSelected, graph, map.extent());
75772             }
75773
75774             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);
75775             dispatch$1.call('drawn', this, {
75776               full: true
75777             });
75778           }
75779
75780           map.init = function () {
75781             drawLayers = svgLayers(projection, context);
75782             drawPoints = svgPoints(projection, context);
75783             drawVertices = svgVertices(projection, context);
75784             drawLines = svgLines(projection, context);
75785             drawAreas = svgAreas(projection, context);
75786             drawMidpoints = svgMidpoints(projection, context);
75787             drawLabels = svgLabels(projection, context);
75788           };
75789
75790           function editOff() {
75791             context.features().resetStats();
75792             surface.selectAll('.layer-osm *').remove();
75793             surface.selectAll('.layer-touch:not(.markers) *').remove();
75794             var allowed = {
75795               'browse': true,
75796               'save': true,
75797               'select-note': true,
75798               'select-data': true,
75799               'select-error': true
75800             };
75801             var mode = context.mode();
75802
75803             if (mode && !allowed[mode.id]) {
75804               context.enter(modeBrowse(context));
75805             }
75806
75807             dispatch$1.call('drawn', this, {
75808               full: true
75809             });
75810           }
75811
75812           function gestureChange(d3_event) {
75813             // Remap Safari gesture events to wheel events - #5492
75814             // We want these disabled most places, but enabled for zoom/unzoom on map surface
75815             // https://developer.mozilla.org/en-US/docs/Web/API/GestureEvent
75816             var e = d3_event;
75817             e.preventDefault();
75818             var props = {
75819               deltaMode: 0,
75820               // dummy values to ignore in zoomPan
75821               deltaY: 1,
75822               // dummy values to ignore in zoomPan
75823               clientX: e.clientX,
75824               clientY: e.clientY,
75825               screenX: e.screenX,
75826               screenY: e.screenY,
75827               x: e.x,
75828               y: e.y
75829             };
75830             var e2 = new WheelEvent('wheel', props);
75831             e2._scale = e.scale; // preserve the original scale
75832
75833             e2._rotation = e.rotation; // preserve the original rotation
75834
75835             _selection.node().dispatchEvent(e2);
75836           }
75837
75838           function zoomPan(event, key, transform) {
75839             var source = event && event.sourceEvent || event;
75840             var eventTransform = transform || event && event.transform;
75841             var x = eventTransform.x;
75842             var y = eventTransform.y;
75843             var k = eventTransform.k; // Special handling of 'wheel' events:
75844             // They might be triggered by the user scrolling the mouse wheel,
75845             // or 2-finger pinch/zoom gestures, the transform may need adjustment.
75846
75847             if (source && source.type === 'wheel') {
75848               // assume that the gesture is already handled by pointer events
75849               if (_pointerDown) return;
75850               var detected = utilDetect();
75851               var dX = source.deltaX;
75852               var dY = source.deltaY;
75853               var x2 = x;
75854               var y2 = y;
75855               var k2 = k;
75856               var t0, p0, p1; // Normalize mousewheel scroll speed (Firefox) - #3029
75857               // If wheel delta is provided in LINE units, recalculate it in PIXEL units
75858               // We are essentially redoing the calculations that occur here:
75859               //   https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
75860               // See this for more info:
75861               //   https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
75862
75863               if (source.deltaMode === 1
75864               /* LINE */
75865               ) {
75866                   // Convert from lines to pixels, more if the user is scrolling fast.
75867                   // (I made up the exp function to roughly match Firefox to what Chrome does)
75868                   // These numbers should be floats, because integers are treated as pan gesture below.
75869                   var lines = Math.abs(source.deltaY);
75870                   var sign = source.deltaY > 0 ? 1 : -1;
75871                   dY = sign * clamp(Math.exp((lines - 1) * 0.75) * 4.000244140625, 4.000244140625, // min
75872                   350.000244140625 // max
75873                   ); // On Firefox Windows and Linux we always get +/- the scroll line amount (default 3)
75874                   // There doesn't seem to be any scroll acceleration.
75875                   // This multiplier increases the speed a little bit - #5512
75876
75877                   if (detected.os !== 'mac') {
75878                     dY *= 5;
75879                   } // recalculate x2,y2,k2
75880
75881
75882                   t0 = _isTransformed ? _transformLast : _transformStart;
75883                   p0 = _getMouseCoords(source);
75884                   p1 = t0.invert(p0);
75885                   k2 = t0.k * Math.pow(2, -dY / 500);
75886                   k2 = clamp(k2, kMin, kMax);
75887                   x2 = p0[0] - p1[0] * k2;
75888                   y2 = p0[1] - p1[1] * k2; // 2 finger map pinch zooming (Safari) - #5492
75889                   // These are fake `wheel` events we made from Safari `gesturechange` events..
75890                 } else if (source._scale) {
75891                 // recalculate x2,y2,k2
75892                 t0 = _gestureTransformStart;
75893                 p0 = _getMouseCoords(source);
75894                 p1 = t0.invert(p0);
75895                 k2 = t0.k * source._scale;
75896                 k2 = clamp(k2, kMin, kMax);
75897                 x2 = p0[0] - p1[0] * k2;
75898                 y2 = p0[1] - p1[1] * k2; // 2 finger map pinch zooming (all browsers except Safari) - #5492
75899                 // Pinch zooming via the `wheel` event will always have:
75900                 // - `ctrlKey = true`
75901                 // - `deltaY` is not round integer pixels (ignore `deltaX`)
75902               } else if (source.ctrlKey && !isInteger(dY)) {
75903                 dY *= 6; // slightly scale up whatever the browser gave us
75904                 // recalculate x2,y2,k2
75905
75906                 t0 = _isTransformed ? _transformLast : _transformStart;
75907                 p0 = _getMouseCoords(source);
75908                 p1 = t0.invert(p0);
75909                 k2 = t0.k * Math.pow(2, -dY / 500);
75910                 k2 = clamp(k2, kMin, kMax);
75911                 x2 = p0[0] - p1[0] * k2;
75912                 y2 = p0[1] - p1[1] * k2; // Trackpad scroll zooming with shift or alt/option key down
75913               } else if ((source.altKey || source.shiftKey) && isInteger(dY)) {
75914                 // recalculate x2,y2,k2
75915                 t0 = _isTransformed ? _transformLast : _transformStart;
75916                 p0 = _getMouseCoords(source);
75917                 p1 = t0.invert(p0);
75918                 k2 = t0.k * Math.pow(2, -dY / 500);
75919                 k2 = clamp(k2, kMin, kMax);
75920                 x2 = p0[0] - p1[0] * k2;
75921                 y2 = p0[1] - p1[1] * k2; // 2 finger map panning (Mac only, all browsers) - #5492, #5512
75922                 // Panning via the `wheel` event will always have:
75923                 // - `ctrlKey = false`
75924                 // - `deltaX`,`deltaY` are round integer pixels
75925               } else if (detected.os === 'mac' && !source.ctrlKey && isInteger(dX) && isInteger(dY)) {
75926                 p1 = projection.translate();
75927                 x2 = p1[0] - dX;
75928                 y2 = p1[1] - dY;
75929                 k2 = projection.scale();
75930                 k2 = clamp(k2, kMin, kMax);
75931               } // something changed - replace the event transform
75932
75933
75934               if (x2 !== x || y2 !== y || k2 !== k) {
75935                 x = x2;
75936                 y = y2;
75937                 k = k2;
75938                 eventTransform = identity$2.translate(x2, y2).scale(k2);
75939
75940                 if (_zoomerPanner._transform) {
75941                   // utilZoomPan interface
75942                   _zoomerPanner._transform(eventTransform);
75943                 } else {
75944                   // d3_zoom interface
75945                   _selection.node().__zoom = eventTransform;
75946                 }
75947               }
75948             }
75949
75950             if (_transformStart.x === x && _transformStart.y === y && _transformStart.k === k) {
75951               return; // no change
75952             }
75953
75954             var withinEditableZoom = map.withinEditableZoom();
75955
75956             if (_lastWithinEditableZoom !== withinEditableZoom) {
75957               if (_lastWithinEditableZoom !== undefined) {
75958                 // notify that the map zoomed in or out over the editable zoom threshold
75959                 dispatch$1.call('crossEditableZoom', this, withinEditableZoom);
75960               }
75961
75962               _lastWithinEditableZoom = withinEditableZoom;
75963             }
75964
75965             if (geoScaleToZoom(k, TILESIZE) < _minzoom) {
75966               surface.interrupt();
75967               dispatch$1.call('hitMinZoom', this, map);
75968               setCenterZoom(map.center(), context.minEditableZoom(), 0, true);
75969               scheduleRedraw();
75970               dispatch$1.call('move', this, map);
75971               return;
75972             }
75973
75974             projection.transform(eventTransform);
75975             var scale = k / _transformStart.k;
75976             var tX = (x / scale - _transformStart.x) * scale;
75977             var tY = (y / scale - _transformStart.y) * scale;
75978
75979             if (context.inIntro()) {
75980               curtainProjection.transform({
75981                 x: x - tX,
75982                 y: y - tY,
75983                 k: k
75984               });
75985             }
75986
75987             if (source) {
75988               _lastPointerEvent = event;
75989             }
75990
75991             _isTransformed = true;
75992             _transformLast = eventTransform;
75993             utilSetTransform(supersurface, tX, tY, scale);
75994             scheduleRedraw();
75995             dispatch$1.call('move', this, map);
75996
75997             function isInteger(val) {
75998               return typeof val === 'number' && isFinite(val) && Math.floor(val) === val;
75999             }
76000           }
76001
76002           function resetTransform() {
76003             if (!_isTransformed) return false;
76004             utilSetTransform(supersurface, 0, 0);
76005             _isTransformed = false;
76006
76007             if (context.inIntro()) {
76008               curtainProjection.transform(projection.transform());
76009             }
76010
76011             return true;
76012           }
76013
76014           function redraw(difference, extent) {
76015             if (surface.empty() || !_redrawEnabled) return; // If we are in the middle of a zoom/pan, we can't do differenced redraws.
76016             // It would result in artifacts where differenced entities are redrawn with
76017             // one transform and unchanged entities with another.
76018
76019             if (resetTransform()) {
76020               difference = extent = undefined;
76021             }
76022
76023             var zoom = map.zoom();
76024             var z = String(~~zoom);
76025
76026             if (surface.attr('data-zoom') !== z) {
76027               surface.attr('data-zoom', z);
76028             } // class surface as `lowzoom` around z17-z18.5 (based on latitude)
76029
76030
76031             var lat = map.center()[1];
76032             var lowzoom = linear$2().domain([-60, 0, 60]).range([17, 18.5, 17]).clamp(true);
76033             surface.classed('low-zoom', zoom <= lowzoom(lat));
76034
76035             if (!difference) {
76036               supersurface.call(context.background());
76037               wrapper.call(drawLayers);
76038             } // OSM
76039
76040
76041             if (map.editableDataEnabled() || map.isInWideSelection()) {
76042               context.loadTiles(projection);
76043               drawEditable(difference, extent);
76044             } else {
76045               editOff();
76046             }
76047
76048             _transformStart = projection.transform();
76049             return map;
76050           }
76051
76052           var immediateRedraw = function immediateRedraw(difference, extent) {
76053             if (!difference && !extent) cancelPendingRedraw();
76054             redraw(difference, extent);
76055           };
76056
76057           map.lastPointerEvent = function () {
76058             return _lastPointerEvent;
76059           };
76060
76061           map.mouse = function (d3_event) {
76062             var event = _lastPointerEvent || d3_event;
76063
76064             if (event) {
76065               var s;
76066
76067               while (s = event.sourceEvent) {
76068                 event = s;
76069               }
76070
76071               return _getMouseCoords(event);
76072             }
76073
76074             return null;
76075           }; // returns Lng/Lat
76076
76077
76078           map.mouseCoordinates = function () {
76079             var coord = map.mouse() || pxCenter();
76080             return projection.invert(coord);
76081           };
76082
76083           map.dblclickZoomEnable = function (val) {
76084             if (!arguments.length) return _dblClickZoomEnabled;
76085             _dblClickZoomEnabled = val;
76086             return map;
76087           };
76088
76089           map.redrawEnable = function (val) {
76090             if (!arguments.length) return _redrawEnabled;
76091             _redrawEnabled = val;
76092             return map;
76093           };
76094
76095           map.isTransformed = function () {
76096             return _isTransformed;
76097           };
76098
76099           function setTransform(t2, duration, force) {
76100             var t = projection.transform();
76101             if (!force && t2.k === t.k && t2.x === t.x && t2.y === t.y) return false;
76102
76103             if (duration) {
76104               _selection.transition().duration(duration).on('start', function () {
76105                 map.startEase();
76106               }).call(_zoomerPanner.transform, identity$2.translate(t2.x, t2.y).scale(t2.k));
76107             } else {
76108               projection.transform(t2);
76109               _transformStart = t2;
76110
76111               _selection.call(_zoomerPanner.transform, _transformStart);
76112             }
76113
76114             return true;
76115           }
76116
76117           function setCenterZoom(loc2, z2, duration, force) {
76118             var c = map.center();
76119             var z = map.zoom();
76120             if (loc2[0] === c[0] && loc2[1] === c[1] && z2 === z && !force) return false;
76121             var proj = geoRawMercator().transform(projection.transform()); // copy projection
76122
76123             var k2 = clamp(geoZoomToScale(z2, TILESIZE), kMin, kMax);
76124             proj.scale(k2);
76125             var t = proj.translate();
76126             var point = proj(loc2);
76127             var center = pxCenter();
76128             t[0] += center[0] - point[0];
76129             t[1] += center[1] - point[1];
76130             return setTransform(identity$2.translate(t[0], t[1]).scale(k2), duration, force);
76131           }
76132
76133           map.pan = function (delta, duration) {
76134             var t = projection.translate();
76135             var k = projection.scale();
76136             t[0] += delta[0];
76137             t[1] += delta[1];
76138
76139             if (duration) {
76140               _selection.transition().duration(duration).on('start', function () {
76141                 map.startEase();
76142               }).call(_zoomerPanner.transform, identity$2.translate(t[0], t[1]).scale(k));
76143             } else {
76144               projection.translate(t);
76145               _transformStart = projection.transform();
76146
76147               _selection.call(_zoomerPanner.transform, _transformStart);
76148
76149               dispatch$1.call('move', this, map);
76150               immediateRedraw();
76151             }
76152
76153             return map;
76154           };
76155
76156           map.dimensions = function (val) {
76157             if (!arguments.length) return _dimensions;
76158             _dimensions = val;
76159             drawLayers.dimensions(_dimensions);
76160             context.background().dimensions(_dimensions);
76161             projection.clipExtent([[0, 0], _dimensions]);
76162             _getMouseCoords = utilFastMouse(supersurface.node());
76163             scheduleRedraw();
76164             return map;
76165           };
76166
76167           function zoomIn(delta) {
76168             setCenterZoom(map.center(), ~~map.zoom() + delta, 250, true);
76169           }
76170
76171           function zoomOut(delta) {
76172             setCenterZoom(map.center(), ~~map.zoom() - delta, 250, true);
76173           }
76174
76175           map.zoomIn = function () {
76176             zoomIn(1);
76177           };
76178
76179           map.zoomInFurther = function () {
76180             zoomIn(4);
76181           };
76182
76183           map.canZoomIn = function () {
76184             return map.zoom() < maxZoom;
76185           };
76186
76187           map.zoomOut = function () {
76188             zoomOut(1);
76189           };
76190
76191           map.zoomOutFurther = function () {
76192             zoomOut(4);
76193           };
76194
76195           map.canZoomOut = function () {
76196             return map.zoom() > minZoom;
76197           };
76198
76199           map.center = function (loc2) {
76200             if (!arguments.length) {
76201               return projection.invert(pxCenter());
76202             }
76203
76204             if (setCenterZoom(loc2, map.zoom())) {
76205               dispatch$1.call('move', this, map);
76206             }
76207
76208             scheduleRedraw();
76209             return map;
76210           };
76211
76212           map.unobscuredCenterZoomEase = function (loc, zoom) {
76213             var offset = map.unobscuredOffsetPx();
76214             var proj = geoRawMercator().transform(projection.transform()); // copy projection
76215             // use the target zoom to calculate the offset center
76216
76217             proj.scale(geoZoomToScale(zoom, TILESIZE));
76218             var locPx = proj(loc);
76219             var offsetLocPx = [locPx[0] + offset[0], locPx[1] + offset[1]];
76220             var offsetLoc = proj.invert(offsetLocPx);
76221             map.centerZoomEase(offsetLoc, zoom);
76222           };
76223
76224           map.unobscuredOffsetPx = function () {
76225             var openPane = context.container().select('.map-panes .map-pane.shown');
76226
76227             if (!openPane.empty()) {
76228               return [openPane.node().offsetWidth / 2, 0];
76229             }
76230
76231             return [0, 0];
76232           };
76233
76234           map.zoom = function (z2) {
76235             if (!arguments.length) {
76236               return Math.max(geoScaleToZoom(projection.scale(), TILESIZE), 0);
76237             }
76238
76239             if (z2 < _minzoom) {
76240               surface.interrupt();
76241               dispatch$1.call('hitMinZoom', this, map);
76242               z2 = context.minEditableZoom();
76243             }
76244
76245             if (setCenterZoom(map.center(), z2)) {
76246               dispatch$1.call('move', this, map);
76247             }
76248
76249             scheduleRedraw();
76250             return map;
76251           };
76252
76253           map.centerZoom = function (loc2, z2) {
76254             if (setCenterZoom(loc2, z2)) {
76255               dispatch$1.call('move', this, map);
76256             }
76257
76258             scheduleRedraw();
76259             return map;
76260           };
76261
76262           map.zoomTo = function (entity) {
76263             var extent = entity.extent(context.graph());
76264             if (!isFinite(extent.area())) return map;
76265             var z2 = clamp(map.trimmedExtentZoom(extent), 0, 20);
76266             return map.centerZoom(extent.center(), z2);
76267           };
76268
76269           map.centerEase = function (loc2, duration) {
76270             duration = duration || 250;
76271             setCenterZoom(loc2, map.zoom(), duration);
76272             return map;
76273           };
76274
76275           map.zoomEase = function (z2, duration) {
76276             duration = duration || 250;
76277             setCenterZoom(map.center(), z2, duration, false);
76278             return map;
76279           };
76280
76281           map.centerZoomEase = function (loc2, z2, duration) {
76282             duration = duration || 250;
76283             setCenterZoom(loc2, z2, duration, false);
76284             return map;
76285           };
76286
76287           map.transformEase = function (t2, duration) {
76288             duration = duration || 250;
76289             setTransform(t2, duration, false
76290             /* don't force */
76291             );
76292             return map;
76293           };
76294
76295           map.zoomToEase = function (obj, duration) {
76296             var extent;
76297
76298             if (Array.isArray(obj)) {
76299               obj.forEach(function (entity) {
76300                 var entityExtent = entity.extent(context.graph());
76301
76302                 if (!extent) {
76303                   extent = entityExtent;
76304                 } else {
76305                   extent = extent.extend(entityExtent);
76306                 }
76307               });
76308             } else {
76309               extent = obj.extent(context.graph());
76310             }
76311
76312             if (!isFinite(extent.area())) return map;
76313             var z2 = clamp(map.trimmedExtentZoom(extent), 0, 20);
76314             return map.centerZoomEase(extent.center(), z2, duration);
76315           };
76316
76317           map.startEase = function () {
76318             utilBindOnce(surface, _pointerPrefix + 'down.ease', function () {
76319               map.cancelEase();
76320             });
76321             return map;
76322           };
76323
76324           map.cancelEase = function () {
76325             _selection.interrupt();
76326
76327             return map;
76328           };
76329
76330           map.extent = function (val) {
76331             if (!arguments.length) {
76332               return new geoExtent(projection.invert([0, _dimensions[1]]), projection.invert([_dimensions[0], 0]));
76333             } else {
76334               var extent = geoExtent(val);
76335               map.centerZoom(extent.center(), map.extentZoom(extent));
76336             }
76337           };
76338
76339           map.trimmedExtent = function (val) {
76340             if (!arguments.length) {
76341               var headerY = 71;
76342               var footerY = 30;
76343               var pad = 10;
76344               return new geoExtent(projection.invert([pad, _dimensions[1] - footerY - pad]), projection.invert([_dimensions[0] - pad, headerY + pad]));
76345             } else {
76346               var extent = geoExtent(val);
76347               map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
76348             }
76349           };
76350
76351           function calcExtentZoom(extent, dim) {
76352             var tl = projection([extent[0][0], extent[1][1]]);
76353             var br = projection([extent[1][0], extent[0][1]]); // Calculate maximum zoom that fits extent
76354
76355             var hFactor = (br[0] - tl[0]) / dim[0];
76356             var vFactor = (br[1] - tl[1]) / dim[1];
76357             var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
76358             var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
76359             var newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
76360             return newZoom;
76361           }
76362
76363           map.extentZoom = function (val) {
76364             return calcExtentZoom(geoExtent(val), _dimensions);
76365           };
76366
76367           map.trimmedExtentZoom = function (val) {
76368             var trimY = 120;
76369             var trimX = 40;
76370             var trimmed = [_dimensions[0] - trimX, _dimensions[1] - trimY];
76371             return calcExtentZoom(geoExtent(val), trimmed);
76372           };
76373
76374           map.withinEditableZoom = function () {
76375             return map.zoom() >= context.minEditableZoom();
76376           };
76377
76378           map.isInWideSelection = function () {
76379             return !map.withinEditableZoom() && context.selectedIDs().length;
76380           };
76381
76382           map.editableDataEnabled = function (skipZoomCheck) {
76383             var layer = context.layers().layer('osm');
76384             if (!layer || !layer.enabled()) return false;
76385             return skipZoomCheck || map.withinEditableZoom();
76386           };
76387
76388           map.notesEditable = function () {
76389             var layer = context.layers().layer('notes');
76390             if (!layer || !layer.enabled()) return false;
76391             return map.withinEditableZoom();
76392           };
76393
76394           map.minzoom = function (val) {
76395             if (!arguments.length) return _minzoom;
76396             _minzoom = val;
76397             return map;
76398           };
76399
76400           map.toggleHighlightEdited = function () {
76401             surface.classed('highlight-edited', !surface.classed('highlight-edited'));
76402             map.pan([0, 0]); // trigger a redraw
76403
76404             dispatch$1.call('changeHighlighting', this);
76405           };
76406
76407           map.areaFillOptions = ['wireframe', 'partial', 'full'];
76408
76409           map.activeAreaFill = function (val) {
76410             if (!arguments.length) return corePreferences('area-fill') || 'partial';
76411             corePreferences('area-fill', val);
76412
76413             if (val !== 'wireframe') {
76414               corePreferences('area-fill-toggle', val);
76415             }
76416
76417             updateAreaFill();
76418             map.pan([0, 0]); // trigger a redraw
76419
76420             dispatch$1.call('changeAreaFill', this);
76421             return map;
76422           };
76423
76424           map.toggleWireframe = function () {
76425             var activeFill = map.activeAreaFill();
76426
76427             if (activeFill === 'wireframe') {
76428               activeFill = corePreferences('area-fill-toggle') || 'partial';
76429             } else {
76430               activeFill = 'wireframe';
76431             }
76432
76433             map.activeAreaFill(activeFill);
76434           };
76435
76436           function updateAreaFill() {
76437             var activeFill = map.activeAreaFill();
76438             map.areaFillOptions.forEach(function (opt) {
76439               surface.classed('fill-' + opt, Boolean(opt === activeFill));
76440             });
76441           }
76442
76443           map.layers = function () {
76444             return drawLayers;
76445           };
76446
76447           map.doubleUpHandler = function () {
76448             return _doubleUpHandler;
76449           };
76450
76451           return utilRebind(map, dispatch$1, 'on');
76452         }
76453
76454         function rendererPhotos(context) {
76455           var dispatch$1 = dispatch('change');
76456           var _layerIDs = ['streetside', 'mapillary', 'mapillary-map-features', 'mapillary-signs', 'openstreetcam'];
76457           var _allPhotoTypes = ['flat', 'panoramic'];
76458
76459           var _shownPhotoTypes = _allPhotoTypes.slice(); // shallow copy
76460
76461
76462           var _dateFilters = ['fromDate', 'toDate'];
76463
76464           var _fromDate;
76465
76466           var _toDate;
76467
76468           var _usernames;
76469
76470           function photos() {}
76471
76472           function updateStorage() {
76473             if (window.mocha) return;
76474             var hash = utilStringQs(window.location.hash);
76475             var enabled = context.layers().all().filter(function (d) {
76476               return _layerIDs.indexOf(d.id) !== -1 && d.layer && d.layer.supported() && d.layer.enabled();
76477             }).map(function (d) {
76478               return d.id;
76479             });
76480
76481             if (enabled.length) {
76482               hash.photo_overlay = enabled.join(',');
76483             } else {
76484               delete hash.photo_overlay;
76485             }
76486
76487             window.location.replace('#' + utilQsString(hash, true));
76488           }
76489
76490           photos.overlayLayerIDs = function () {
76491             return _layerIDs;
76492           };
76493
76494           photos.allPhotoTypes = function () {
76495             return _allPhotoTypes;
76496           };
76497
76498           photos.dateFilters = function () {
76499             return _dateFilters;
76500           };
76501
76502           photos.dateFilterValue = function (val) {
76503             return val === _dateFilters[0] ? _fromDate : _toDate;
76504           };
76505
76506           photos.setDateFilter = function (type, val, updateUrl) {
76507             // validate the date
76508             var date = val && new Date(val);
76509
76510             if (date && !isNaN(date)) {
76511               val = date.toISOString().substr(0, 10);
76512             } else {
76513               val = null;
76514             }
76515
76516             if (type === _dateFilters[0]) {
76517               _fromDate = val;
76518
76519               if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
76520                 _toDate = _fromDate;
76521               }
76522             }
76523
76524             if (type === _dateFilters[1]) {
76525               _toDate = val;
76526
76527               if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
76528                 _fromDate = _toDate;
76529               }
76530             }
76531
76532             dispatch$1.call('change', this);
76533
76534             if (updateUrl) {
76535               var rangeString;
76536
76537               if (_fromDate || _toDate) {
76538                 rangeString = (_fromDate || '') + '_' + (_toDate || '');
76539               }
76540
76541               setUrlFilterValue('photo_dates', rangeString);
76542             }
76543           };
76544
76545           photos.setUsernameFilter = function (val, updateUrl) {
76546             if (val && typeof val === 'string') val = val.replace(/;/g, ',').split(',');
76547
76548             if (val) {
76549               val = val.map(function (d) {
76550                 return d.trim();
76551               }).filter(Boolean);
76552
76553               if (!val.length) {
76554                 val = null;
76555               }
76556             }
76557
76558             _usernames = val;
76559             dispatch$1.call('change', this);
76560
76561             if (updateUrl) {
76562               var hashString;
76563
76564               if (_usernames) {
76565                 hashString = _usernames.join(',');
76566               }
76567
76568               setUrlFilterValue('photo_username', hashString);
76569             }
76570           };
76571
76572           function setUrlFilterValue(property, val) {
76573             if (!window.mocha) {
76574               var hash = utilStringQs(window.location.hash);
76575
76576               if (val) {
76577                 if (hash[property] === val) return;
76578                 hash[property] = val;
76579               } else {
76580                 if (!(property in hash)) return;
76581                 delete hash[property];
76582               }
76583
76584               window.location.replace('#' + utilQsString(hash, true));
76585             }
76586           }
76587
76588           function showsLayer(id) {
76589             var layer = context.layers().layer(id);
76590             return layer && layer.supported() && layer.enabled();
76591           }
76592
76593           photos.shouldFilterByDate = function () {
76594             return showsLayer('mapillary') || showsLayer('openstreetcam') || showsLayer('streetside');
76595           };
76596
76597           photos.shouldFilterByPhotoType = function () {
76598             return showsLayer('mapillary') || showsLayer('streetside') && showsLayer('openstreetcam');
76599           };
76600
76601           photos.shouldFilterByUsername = function () {
76602             return showsLayer('mapillary') || showsLayer('openstreetcam') || showsLayer('streetside');
76603           };
76604
76605           photos.showsPhotoType = function (val) {
76606             if (!photos.shouldFilterByPhotoType()) return true;
76607             return _shownPhotoTypes.indexOf(val) !== -1;
76608           };
76609
76610           photos.showsFlat = function () {
76611             return photos.showsPhotoType('flat');
76612           };
76613
76614           photos.showsPanoramic = function () {
76615             return photos.showsPhotoType('panoramic');
76616           };
76617
76618           photos.fromDate = function () {
76619             return _fromDate;
76620           };
76621
76622           photos.toDate = function () {
76623             return _toDate;
76624           };
76625
76626           photos.togglePhotoType = function (val) {
76627             var index = _shownPhotoTypes.indexOf(val);
76628
76629             if (index !== -1) {
76630               _shownPhotoTypes.splice(index, 1);
76631             } else {
76632               _shownPhotoTypes.push(val);
76633             }
76634
76635             dispatch$1.call('change', this);
76636             return photos;
76637           };
76638
76639           photos.usernames = function () {
76640             return _usernames;
76641           };
76642
76643           photos.init = function () {
76644             var hash = utilStringQs(window.location.hash);
76645
76646             if (hash.photo_dates) {
76647               // expect format like `photo_dates=2019-01-01_2020-12-31`, but allow a couple different separators
76648               var parts = /^(.*)[–_](.*)$/g.exec(hash.photo_dates.trim());
76649               this.setDateFilter('fromDate', parts && parts.length >= 2 && parts[1], false);
76650               this.setDateFilter('toDate', parts && parts.length >= 3 && parts[2], false);
76651             }
76652
76653             if (hash.photo_username) {
76654               this.setUsernameFilter(hash.photo_username, false);
76655             }
76656
76657             if (hash.photo_overlay) {
76658               // support enabling photo layers by default via a URL parameter, e.g. `photo_overlay=openstreetcam;mapillary;streetside`
76659               var hashOverlayIDs = hash.photo_overlay.replace(/;/g, ',').split(',');
76660               hashOverlayIDs.forEach(function (id) {
76661                 var layer = _layerIDs.indexOf(id) !== -1 && context.layers().layer(id);
76662                 if (layer && !layer.enabled()) layer.enabled(true);
76663               });
76664             }
76665
76666             if (hash.photo) {
76667               // support opening a photo via a URL parameter, e.g. `photo=mapillary-fztgSDtLpa08ohPZFZjeRQ`
76668               var photoIds = hash.photo.replace(/;/g, ',').split(',');
76669               var photoId = photoIds.length && photoIds[0].trim();
76670               var results = /(.*)\/(.*)/g.exec(photoId);
76671
76672               if (results && results.length >= 3) {
76673                 var serviceId = results[1];
76674                 var photoKey = results[2];
76675                 var service = services[serviceId];
76676
76677                 if (service && service.ensureViewerLoaded) {
76678                   // if we're showing a photo then make sure its layer is enabled too
76679                   var layer = _layerIDs.indexOf(serviceId) !== -1 && context.layers().layer(serviceId);
76680                   if (layer && !layer.enabled()) layer.enabled(true);
76681                   var baselineTime = Date.now();
76682                   service.on('loadedImages.rendererPhotos', function () {
76683                     // don't open the viewer if too much time has elapsed
76684                     if (Date.now() - baselineTime > 45000) {
76685                       service.on('loadedImages.rendererPhotos', null);
76686                       return;
76687                     }
76688
76689                     if (!service.cachedImage(photoKey)) return;
76690                     service.on('loadedImages.rendererPhotos', null);
76691                     service.ensureViewerLoaded(context).then(function () {
76692                       service.selectImage(context, photoKey).showViewer(context);
76693                     });
76694                   });
76695                 }
76696               }
76697             }
76698
76699             context.layers().on('change.rendererPhotos', updateStorage);
76700           };
76701
76702           return utilRebind(photos, dispatch$1, 'on');
76703         }
76704
76705         function uiAccount(context) {
76706           var osm = context.connection();
76707
76708           function update(selection) {
76709             if (!osm) return;
76710
76711             if (!osm.authenticated()) {
76712               selection.selectAll('.userLink, .logoutLink').classed('hide', true);
76713               return;
76714             }
76715
76716             osm.userDetails(function (err, details) {
76717               var userLink = selection.select('.userLink'),
76718                   logoutLink = selection.select('.logoutLink');
76719               userLink.html('');
76720               logoutLink.html('');
76721               if (err || !details) return;
76722               selection.selectAll('.userLink, .logoutLink').classed('hide', false); // Link
76723
76724               var userLinkA = userLink.append('a').attr('href', osm.userURL(details.display_name)).attr('target', '_blank'); // Add thumbnail or dont
76725
76726               if (details.image_url) {
76727                 userLinkA.append('img').attr('class', 'icon pre-text user-icon').attr('src', details.image_url);
76728               } else {
76729                 userLinkA.call(svgIcon('#iD-icon-avatar', 'pre-text light'));
76730               } // Add user name
76731
76732
76733               userLinkA.append('span').attr('class', 'label').html(details.display_name);
76734               logoutLink.append('a').attr('class', 'logout').attr('href', '#').html(_t.html('logout')).on('click.logout', function (d3_event) {
76735                 d3_event.preventDefault();
76736                 osm.logout();
76737               });
76738             });
76739           }
76740
76741           return function (selection) {
76742             selection.append('li').attr('class', 'userLink').classed('hide', true);
76743             selection.append('li').attr('class', 'logoutLink').classed('hide', true);
76744
76745             if (osm) {
76746               osm.on('change.account', function () {
76747                 update(selection);
76748               });
76749               update(selection);
76750             }
76751           };
76752         }
76753
76754         function uiAttribution(context) {
76755           var _selection = select(null);
76756
76757           function render(selection, data, klass) {
76758             var div = selection.selectAll(".".concat(klass)).data([0]);
76759             div = div.enter().append('div').attr('class', klass).merge(div);
76760             var attributions = div.selectAll('.attribution').data(data, function (d) {
76761               return d.id;
76762             });
76763             attributions.exit().remove();
76764             attributions = attributions.enter().append('span').attr('class', 'attribution').each(function (d, i, nodes) {
76765               var attribution = select(nodes[i]);
76766
76767               if (d.terms_html) {
76768                 attribution.html(d.terms_html);
76769                 return;
76770               }
76771
76772               if (d.terms_url) {
76773                 attribution = attribution.append('a').attr('href', d.terms_url).attr('target', '_blank');
76774               }
76775
76776               var sourceID = d.id.replace(/\./g, '<TX_DOT>');
76777               var terms_text = _t("imagery.".concat(sourceID, ".attribution.text"), {
76778                 "default": d.terms_text || d.id || d.name()
76779               });
76780
76781               if (d.icon && !d.overlay) {
76782                 attribution.append('img').attr('class', 'source-image').attr('src', d.icon);
76783               }
76784
76785               attribution.append('span').attr('class', 'attribution-text').html(terms_text);
76786             }).merge(attributions);
76787             var copyright = attributions.selectAll('.copyright-notice').data(function (d) {
76788               var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
76789               return notice ? [notice] : [];
76790             });
76791             copyright.exit().remove();
76792             copyright = copyright.enter().append('span').attr('class', 'copyright-notice').merge(copyright);
76793             copyright.html(String);
76794           }
76795
76796           function update() {
76797             var baselayer = context.background().baseLayerSource();
76798
76799             _selection.call(render, baselayer ? [baselayer] : [], 'base-layer-attribution');
76800
76801             var z = context.map().zoom();
76802             var overlays = context.background().overlayLayerSources() || [];
76803
76804             _selection.call(render, overlays.filter(function (s) {
76805               return s.validZoom(z);
76806             }), 'overlay-layer-attribution');
76807           }
76808
76809           return function (selection) {
76810             _selection = selection;
76811             context.background().on('change.attribution', update);
76812             context.map().on('move.attribution', throttle(update, 400, {
76813               leading: false
76814             }));
76815             update();
76816           };
76817         }
76818
76819         function uiContributors(context) {
76820           var osm = context.connection(),
76821               debouncedUpdate = debounce(function () {
76822             update();
76823           }, 1000),
76824               limit = 4,
76825               hidden = false,
76826               wrap = select(null);
76827
76828           function update() {
76829             if (!osm) return;
76830             var users = {},
76831                 entities = context.history().intersects(context.map().extent());
76832             entities.forEach(function (entity) {
76833               if (entity && entity.user) users[entity.user] = true;
76834             });
76835             var u = Object.keys(users),
76836                 subset = u.slice(0, u.length > limit ? limit - 1 : limit);
76837             wrap.html('').call(svgIcon('#iD-icon-nearby', 'pre-text light'));
76838             var userList = select(document.createElement('span'));
76839             userList.selectAll().data(subset).enter().append('a').attr('class', 'user-link').attr('href', function (d) {
76840               return osm.userURL(d);
76841             }).attr('target', '_blank').html(String);
76842
76843             if (u.length > limit) {
76844               var count = select(document.createElement('span'));
76845               var othersNum = u.length - limit + 1;
76846               count.append('a').attr('target', '_blank').attr('href', function () {
76847                 return osm.changesetsURL(context.map().center(), context.map().zoom());
76848               }).html(othersNum);
76849               wrap.append('span').html(_t.html('contributors.truncated_list', {
76850                 n: othersNum,
76851                 users: userList.html(),
76852                 count: count.html()
76853               }));
76854             } else {
76855               wrap.append('span').html(_t.html('contributors.list', {
76856                 users: userList.html()
76857               }));
76858             }
76859
76860             if (!u.length) {
76861               hidden = true;
76862               wrap.transition().style('opacity', 0);
76863             } else if (hidden) {
76864               wrap.transition().style('opacity', 1);
76865             }
76866           }
76867
76868           return function (selection) {
76869             if (!osm) return;
76870             wrap = selection;
76871             update();
76872             osm.on('loaded.contributors', debouncedUpdate);
76873             context.map().on('move.contributors', debouncedUpdate);
76874           };
76875         }
76876
76877         var _popoverID = 0;
76878         function uiPopover(klass) {
76879           var _id = _popoverID++;
76880
76881           var _anchorSelection = select(null);
76882
76883           var popover = function popover(selection) {
76884             _anchorSelection = selection;
76885             selection.each(setup);
76886           };
76887
76888           var _animation = utilFunctor(false);
76889
76890           var _placement = utilFunctor('top'); // top, bottom, left, right
76891
76892
76893           var _alignment = utilFunctor('center'); // leading, center, trailing
76894
76895
76896           var _scrollContainer = utilFunctor(select(null));
76897
76898           var _content;
76899
76900           var _displayType = utilFunctor('');
76901
76902           var _hasArrow = utilFunctor(true); // use pointer events on supported platforms; fallback to mouse events
76903
76904
76905           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
76906
76907           popover.displayType = function (val) {
76908             if (arguments.length) {
76909               _displayType = utilFunctor(val);
76910               return popover;
76911             } else {
76912               return _displayType;
76913             }
76914           };
76915
76916           popover.hasArrow = function (val) {
76917             if (arguments.length) {
76918               _hasArrow = utilFunctor(val);
76919               return popover;
76920             } else {
76921               return _hasArrow;
76922             }
76923           };
76924
76925           popover.placement = function (val) {
76926             if (arguments.length) {
76927               _placement = utilFunctor(val);
76928               return popover;
76929             } else {
76930               return _placement;
76931             }
76932           };
76933
76934           popover.alignment = function (val) {
76935             if (arguments.length) {
76936               _alignment = utilFunctor(val);
76937               return popover;
76938             } else {
76939               return _alignment;
76940             }
76941           };
76942
76943           popover.scrollContainer = function (val) {
76944             if (arguments.length) {
76945               _scrollContainer = utilFunctor(val);
76946               return popover;
76947             } else {
76948               return _scrollContainer;
76949             }
76950           };
76951
76952           popover.content = function (val) {
76953             if (arguments.length) {
76954               _content = val;
76955               return popover;
76956             } else {
76957               return _content;
76958             }
76959           };
76960
76961           popover.isShown = function () {
76962             var popoverSelection = _anchorSelection.select('.popover-' + _id);
76963
76964             return !popoverSelection.empty() && popoverSelection.classed('in');
76965           };
76966
76967           popover.show = function () {
76968             _anchorSelection.each(show);
76969           };
76970
76971           popover.updateContent = function () {
76972             _anchorSelection.each(updateContent);
76973           };
76974
76975           popover.hide = function () {
76976             _anchorSelection.each(hide);
76977           };
76978
76979           popover.toggle = function () {
76980             _anchorSelection.each(toggle);
76981           };
76982
76983           popover.destroy = function (selection, selector) {
76984             // by default, just destroy the current popover
76985             selector = selector || '.popover-' + _id;
76986             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 () {
76987               return this.getAttribute('data-original-title') || this.getAttribute('title');
76988             }).attr('data-original-title', null).selectAll(selector).remove();
76989           };
76990
76991           popover.destroyAny = function (selection) {
76992             selection.call(popover.destroy, '.popover');
76993           };
76994
76995           function setup() {
76996             var anchor = select(this);
76997
76998             var animate = _animation.apply(this, arguments);
76999
77000             var popoverSelection = anchor.selectAll('.popover-' + _id).data([0]);
77001             var enter = popoverSelection.enter().append('div').attr('class', 'popover popover-' + _id + ' ' + (klass ? klass : '')).classed('arrowed', _hasArrow.apply(this, arguments));
77002             enter.append('div').attr('class', 'popover-arrow');
77003             enter.append('div').attr('class', 'popover-inner');
77004             popoverSelection = enter.merge(popoverSelection);
77005
77006             if (animate) {
77007               popoverSelection.classed('fade', true);
77008             }
77009
77010             var display = _displayType.apply(this, arguments);
77011
77012             if (display === 'hover') {
77013               var _lastNonMouseEnterTime;
77014
77015               anchor.on(_pointerPrefix + 'enter.popover', function (d3_event) {
77016                 if (d3_event.pointerType) {
77017                   if (d3_event.pointerType !== 'mouse') {
77018                     _lastNonMouseEnterTime = d3_event.timeStamp; // only allow hover behavior for mouse input
77019
77020                     return;
77021                   } else if (_lastNonMouseEnterTime && d3_event.timeStamp - _lastNonMouseEnterTime < 1500) {
77022                     // HACK: iOS 13.4 sends an erroneous `mouse` type pointerenter
77023                     // event for non-mouse interactions right after sending
77024                     // the correct type pointerenter event. Workaround by discarding
77025                     // any mouse event that occurs immediately after a non-mouse event.
77026                     return;
77027                   }
77028                 } // don't show if buttons are pressed, e.g. during click and drag of map
77029
77030
77031                 if (d3_event.buttons !== 0) return;
77032                 show.apply(this, arguments);
77033               }).on(_pointerPrefix + 'leave.popover', function () {
77034                 hide.apply(this, arguments);
77035               }) // show on focus too for better keyboard navigation support
77036               .on('focus.popover', function () {
77037                 show.apply(this, arguments);
77038               }).on('blur.popover', function () {
77039                 hide.apply(this, arguments);
77040               });
77041             } else if (display === 'clickFocus') {
77042               anchor.on(_pointerPrefix + 'down.popover', function (d3_event) {
77043                 d3_event.preventDefault();
77044                 d3_event.stopPropagation();
77045               }).on(_pointerPrefix + 'up.popover', function (d3_event) {
77046                 d3_event.preventDefault();
77047                 d3_event.stopPropagation();
77048               }).on('click.popover', toggle);
77049               popoverSelection // This attribute lets the popover take focus
77050               .attr('tabindex', 0).on('blur.popover', function () {
77051                 anchor.each(function () {
77052                   hide.apply(this, arguments);
77053                 });
77054               });
77055             }
77056           }
77057
77058           function show() {
77059             var anchor = select(this);
77060             var popoverSelection = anchor.selectAll('.popover-' + _id);
77061
77062             if (popoverSelection.empty()) {
77063               // popover was removed somehow, put it back
77064               anchor.call(popover.destroy);
77065               anchor.each(setup);
77066               popoverSelection = anchor.selectAll('.popover-' + _id);
77067             }
77068
77069             popoverSelection.classed('in', true);
77070
77071             var displayType = _displayType.apply(this, arguments);
77072
77073             if (displayType === 'clickFocus') {
77074               anchor.classed('active', true);
77075               popoverSelection.node().focus();
77076             }
77077
77078             anchor.each(updateContent);
77079           }
77080
77081           function updateContent() {
77082             var anchor = select(this);
77083
77084             if (_content) {
77085               anchor.selectAll('.popover-' + _id + ' > .popover-inner').call(_content.apply(this, arguments));
77086             }
77087
77088             updatePosition.apply(this, arguments); // hack: update multiple times to fix instances where the absolute offset is
77089             // set before the dynamic popover size is calculated by the browser
77090
77091             updatePosition.apply(this, arguments);
77092             updatePosition.apply(this, arguments);
77093           }
77094
77095           function updatePosition() {
77096             var anchor = select(this);
77097             var popoverSelection = anchor.selectAll('.popover-' + _id);
77098
77099             var scrollContainer = _scrollContainer && _scrollContainer.apply(this, arguments);
77100
77101             var scrollNode = scrollContainer && !scrollContainer.empty() && scrollContainer.node();
77102             var scrollLeft = scrollNode ? scrollNode.scrollLeft : 0;
77103             var scrollTop = scrollNode ? scrollNode.scrollTop : 0;
77104
77105             var placement = _placement.apply(this, arguments);
77106
77107             popoverSelection.classed('left', false).classed('right', false).classed('top', false).classed('bottom', false).classed(placement, true);
77108
77109             var alignment = _alignment.apply(this, arguments);
77110
77111             var alignFactor = 0.5;
77112
77113             if (alignment === 'leading') {
77114               alignFactor = 0;
77115             } else if (alignment === 'trailing') {
77116               alignFactor = 1;
77117             }
77118
77119             var anchorFrame = getFrame(anchor.node());
77120             var popoverFrame = getFrame(popoverSelection.node());
77121             var position;
77122
77123             switch (placement) {
77124               case 'top':
77125                 position = {
77126                   x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
77127                   y: anchorFrame.y - popoverFrame.h
77128                 };
77129                 break;
77130
77131               case 'bottom':
77132                 position = {
77133                   x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
77134                   y: anchorFrame.y + anchorFrame.h
77135                 };
77136                 break;
77137
77138               case 'left':
77139                 position = {
77140                   x: anchorFrame.x - popoverFrame.w,
77141                   y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
77142                 };
77143                 break;
77144
77145               case 'right':
77146                 position = {
77147                   x: anchorFrame.x + anchorFrame.w,
77148                   y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
77149                 };
77150                 break;
77151             }
77152
77153             if (position) {
77154               if (scrollNode && (placement === 'top' || placement === 'bottom')) {
77155                 var initialPosX = position.x;
77156
77157                 if (position.x + popoverFrame.w > scrollNode.offsetWidth - 10) {
77158                   position.x = scrollNode.offsetWidth - 10 - popoverFrame.w;
77159                 } else if (position.x < 10) {
77160                   position.x = 10;
77161                 }
77162
77163                 var arrow = anchor.selectAll('.popover-' + _id + ' > .popover-arrow'); // keep the arrow centered on the button, or as close as possible
77164
77165                 var arrowPosX = Math.min(Math.max(popoverFrame.w / 2 - (position.x - initialPosX), 10), popoverFrame.w - 10);
77166                 arrow.style('left', ~~arrowPosX + 'px');
77167               }
77168
77169               popoverSelection.style('left', ~~position.x + 'px').style('top', ~~position.y + 'px');
77170             } else {
77171               popoverSelection.style('left', null).style('top', null);
77172             }
77173
77174             function getFrame(node) {
77175               var positionStyle = select(node).style('position');
77176
77177               if (positionStyle === 'absolute' || positionStyle === 'static') {
77178                 return {
77179                   x: node.offsetLeft - scrollLeft,
77180                   y: node.offsetTop - scrollTop,
77181                   w: node.offsetWidth,
77182                   h: node.offsetHeight
77183                 };
77184               } else {
77185                 return {
77186                   x: 0,
77187                   y: 0,
77188                   w: node.offsetWidth,
77189                   h: node.offsetHeight
77190                 };
77191               }
77192             }
77193           }
77194
77195           function hide() {
77196             var anchor = select(this);
77197
77198             if (_displayType.apply(this, arguments) === 'clickFocus') {
77199               anchor.classed('active', false);
77200             }
77201
77202             anchor.selectAll('.popover-' + _id).classed('in', false);
77203           }
77204
77205           function toggle() {
77206             if (select(this).select('.popover-' + _id).classed('in')) {
77207               hide.apply(this, arguments);
77208             } else {
77209               show.apply(this, arguments);
77210             }
77211           }
77212
77213           return popover;
77214         }
77215
77216         function uiTooltip(klass) {
77217           var tooltip = uiPopover((klass || '') + ' tooltip').displayType('hover');
77218
77219           var _title = function _title() {
77220             var title = this.getAttribute('data-original-title');
77221
77222             if (title) {
77223               return title;
77224             } else {
77225               title = this.getAttribute('title');
77226               this.removeAttribute('title');
77227               this.setAttribute('data-original-title', title);
77228             }
77229
77230             return title;
77231           };
77232
77233           var _heading = utilFunctor(null);
77234
77235           var _keys = utilFunctor(null);
77236
77237           tooltip.title = function (val) {
77238             if (!arguments.length) return _title;
77239             _title = utilFunctor(val);
77240             return tooltip;
77241           };
77242
77243           tooltip.heading = function (val) {
77244             if (!arguments.length) return _heading;
77245             _heading = utilFunctor(val);
77246             return tooltip;
77247           };
77248
77249           tooltip.keys = function (val) {
77250             if (!arguments.length) return _keys;
77251             _keys = utilFunctor(val);
77252             return tooltip;
77253           };
77254
77255           tooltip.content(function () {
77256             var heading = _heading.apply(this, arguments);
77257
77258             var text = _title.apply(this, arguments);
77259
77260             var keys = _keys.apply(this, arguments);
77261
77262             return function (selection) {
77263               var headingSelect = selection.selectAll('.tooltip-heading').data(heading ? [heading] : []);
77264               headingSelect.exit().remove();
77265               headingSelect.enter().append('div').attr('class', 'tooltip-heading').merge(headingSelect).html(heading);
77266               var textSelect = selection.selectAll('.tooltip-text').data(text ? [text] : []);
77267               textSelect.exit().remove();
77268               textSelect.enter().append('div').attr('class', 'tooltip-text').merge(textSelect).html(text);
77269               var keyhintWrap = selection.selectAll('.keyhint-wrap').data(keys && keys.length ? [0] : []);
77270               keyhintWrap.exit().remove();
77271               var keyhintWrapEnter = keyhintWrap.enter().append('div').attr('class', 'keyhint-wrap');
77272               keyhintWrapEnter.append('span').html(_t.html('tooltip_keyhint'));
77273               keyhintWrap = keyhintWrapEnter.merge(keyhintWrap);
77274               keyhintWrap.selectAll('kbd.shortcut').data(keys && keys.length ? keys : []).enter().append('kbd').attr('class', 'shortcut').html(function (d) {
77275                 return d;
77276               });
77277             };
77278           });
77279           return tooltip;
77280         }
77281
77282         function uiEditMenu(context) {
77283           var dispatch$1 = dispatch('toggled');
77284
77285           var _menu = select(null);
77286
77287           var _operations = []; // the position the menu should be displayed relative to
77288
77289           var _anchorLoc = [0, 0];
77290           var _anchorLocLonLat = [0, 0]; // a string indicating how the menu was opened
77291
77292           var _triggerType = '';
77293           var _vpTopMargin = 85; // viewport top margin
77294
77295           var _vpBottomMargin = 45; // viewport bottom margin
77296
77297           var _vpSideMargin = 35; // viewport side margin
77298
77299           var _menuTop = false;
77300
77301           var _menuHeight;
77302
77303           var _menuWidth; // hardcode these values to make menu positioning easier
77304
77305
77306           var _verticalPadding = 4; // see also `.edit-menu .tooltip` CSS; include margin
77307
77308           var _tooltipWidth = 210; // offset the menu slightly from the target location
77309
77310           var _menuSideMargin = 10;
77311           var _tooltips = [];
77312
77313           var editMenu = function editMenu(selection) {
77314             var isTouchMenu = _triggerType.includes('touch') || _triggerType.includes('pen');
77315
77316             var ops = _operations.filter(function (op) {
77317               return !isTouchMenu || !op.mouseOnly;
77318             });
77319
77320             if (!ops.length) return;
77321             _tooltips = []; // Position the menu above the anchor for stylus and finger input
77322             // since the mapper's hand likely obscures the screen below the anchor
77323
77324             _menuTop = isTouchMenu; // Show labels for touch input since there aren't hover tooltips
77325
77326             var showLabels = isTouchMenu;
77327             var buttonHeight = showLabels ? 32 : 34;
77328
77329             if (showLabels) {
77330               // Get a general idea of the width based on the length of the label
77331               _menuWidth = 52 + Math.min(120, 6 * Math.max.apply(Math, ops.map(function (op) {
77332                 return op.title.length;
77333               })));
77334             } else {
77335               _menuWidth = 44;
77336             }
77337
77338             _menuHeight = _verticalPadding * 2 + ops.length * buttonHeight;
77339             _menu = selection.append('div').attr('class', 'edit-menu').classed('touch-menu', isTouchMenu).style('padding', _verticalPadding + 'px 0');
77340
77341             var buttons = _menu.selectAll('.edit-menu-item').data(ops); // enter
77342
77343
77344             var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
77345               return 'edit-menu-item edit-menu-item-' + d.id;
77346             }).style('height', buttonHeight + 'px').on('click', click) // don't listen for `mouseup` because we only care about non-mouse pointer types
77347             .on('pointerup', pointerup).on('pointerdown mousedown', function pointerdown(d3_event) {
77348               // don't let button presses also act as map input - #1869
77349               d3_event.stopPropagation();
77350             }).on('mouseenter.highlight', function (d3_event, d) {
77351               if (!d.relatedEntityIds || select(this).classed('disabled')) return;
77352               utilHighlightEntities(d.relatedEntityIds(), true, context);
77353             }).on('mouseleave.highlight', function (d3_event, d) {
77354               if (!d.relatedEntityIds) return;
77355               utilHighlightEntities(d.relatedEntityIds(), false, context);
77356             });
77357             buttonsEnter.each(function (d) {
77358               var tooltip = uiTooltip().heading(d.title).title(d.tooltip()).keys([d.keys[0]]);
77359
77360               _tooltips.push(tooltip);
77361
77362               select(this).call(tooltip).append('div').attr('class', 'icon-wrap').call(svgIcon('#iD-operation-' + d.id, 'operation'));
77363             });
77364
77365             if (showLabels) {
77366               buttonsEnter.append('span').attr('class', 'label').html(function (d) {
77367                 return d.title;
77368               });
77369             } // update
77370
77371
77372             buttonsEnter.merge(buttons).classed('disabled', function (d) {
77373               return d.disabled();
77374             });
77375             updatePosition();
77376             var initialScale = context.projection.scale();
77377             context.map().on('move.edit-menu', function () {
77378               if (initialScale !== context.projection.scale()) {
77379                 editMenu.close();
77380               }
77381             }).on('drawn.edit-menu', function (info) {
77382               if (info.full) updatePosition();
77383             });
77384             var lastPointerUpType; // `pointerup` is always called before `click`
77385
77386             function pointerup(d3_event) {
77387               lastPointerUpType = d3_event.pointerType;
77388             }
77389
77390             function click(d3_event, operation) {
77391               d3_event.stopPropagation();
77392
77393               if (operation.relatedEntityIds) {
77394                 utilHighlightEntities(operation.relatedEntityIds(), false, context);
77395               }
77396
77397               if (operation.disabled()) {
77398                 if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
77399                   // there are no tooltips for touch interactions so flash feedback instead
77400                   context.ui().flash.duration(4000).iconName('#iD-operation-' + operation.id).iconClass('operation disabled').label(operation.tooltip)();
77401                 }
77402               } else {
77403                 if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
77404                   context.ui().flash.duration(2000).iconName('#iD-operation-' + operation.id).iconClass('operation').label(operation.annotation() || operation.title)();
77405                 }
77406
77407                 operation();
77408                 editMenu.close();
77409               }
77410
77411               lastPointerUpType = null;
77412             }
77413
77414             dispatch$1.call('toggled', this, true);
77415           };
77416
77417           function updatePosition() {
77418             if (!_menu || _menu.empty()) return;
77419             var anchorLoc = context.projection(_anchorLocLonLat);
77420             var viewport = context.surfaceRect();
77421
77422             if (anchorLoc[0] < 0 || anchorLoc[0] > viewport.width || anchorLoc[1] < 0 || anchorLoc[1] > viewport.height) {
77423               // close the menu if it's gone offscreen
77424               editMenu.close();
77425               return;
77426             }
77427
77428             var menuLeft = displayOnLeft(viewport);
77429             var offset = [0, 0];
77430             offset[0] = menuLeft ? -1 * (_menuSideMargin + _menuWidth) : _menuSideMargin;
77431
77432             if (_menuTop) {
77433               if (anchorLoc[1] - _menuHeight < _vpTopMargin) {
77434                 // menu is near top viewport edge, shift downward
77435                 offset[1] = -anchorLoc[1] + _vpTopMargin;
77436               } else {
77437                 offset[1] = -_menuHeight;
77438               }
77439             } else {
77440               if (anchorLoc[1] + _menuHeight > viewport.height - _vpBottomMargin) {
77441                 // menu is near bottom viewport edge, shift upwards
77442                 offset[1] = -anchorLoc[1] - _menuHeight + viewport.height - _vpBottomMargin;
77443               } else {
77444                 offset[1] = 0;
77445               }
77446             }
77447
77448             var origin = geoVecAdd(anchorLoc, offset);
77449
77450             _menu.style('left', origin[0] + 'px').style('top', origin[1] + 'px');
77451
77452             var tooltipSide = tooltipPosition(viewport, menuLeft);
77453
77454             _tooltips.forEach(function (tooltip) {
77455               tooltip.placement(tooltipSide);
77456             });
77457
77458             function displayOnLeft(viewport) {
77459               if (_mainLocalizer.textDirection() === 'ltr') {
77460                 if (anchorLoc[0] + _menuSideMargin + _menuWidth > viewport.width - _vpSideMargin) {
77461                   // right menu would be too close to the right viewport edge, go left
77462                   return true;
77463                 } // prefer right menu
77464
77465
77466                 return false;
77467               } else {
77468                 // rtl
77469                 if (anchorLoc[0] - _menuSideMargin - _menuWidth < _vpSideMargin) {
77470                   // left menu would be too close to the left viewport edge, go right
77471                   return false;
77472                 } // prefer left menu
77473
77474
77475                 return true;
77476               }
77477             }
77478
77479             function tooltipPosition(viewport, menuLeft) {
77480               if (_mainLocalizer.textDirection() === 'ltr') {
77481                 if (menuLeft) {
77482                   // if there's not room for a right-side menu then there definitely
77483                   // isn't room for right-side tooltips
77484                   return 'left';
77485                 }
77486
77487                 if (anchorLoc[0] + _menuSideMargin + _menuWidth + _tooltipWidth > viewport.width - _vpSideMargin) {
77488                   // right tooltips would be too close to the right viewport edge, go left
77489                   return 'left';
77490                 } // prefer right tooltips
77491
77492
77493                 return 'right';
77494               } else {
77495                 // rtl
77496                 if (!menuLeft) {
77497                   return 'right';
77498                 }
77499
77500                 if (anchorLoc[0] - _menuSideMargin - _menuWidth - _tooltipWidth < _vpSideMargin) {
77501                   // left tooltips would be too close to the left viewport edge, go right
77502                   return 'right';
77503                 } // prefer left tooltips
77504
77505
77506                 return 'left';
77507               }
77508             }
77509           }
77510
77511           editMenu.close = function () {
77512             context.map().on('move.edit-menu', null).on('drawn.edit-menu', null);
77513
77514             _menu.remove();
77515
77516             _tooltips = [];
77517             dispatch$1.call('toggled', this, false);
77518           };
77519
77520           editMenu.anchorLoc = function (val) {
77521             if (!arguments.length) return _anchorLoc;
77522             _anchorLoc = val;
77523             _anchorLocLonLat = context.projection.invert(_anchorLoc);
77524             return editMenu;
77525           };
77526
77527           editMenu.triggerType = function (val) {
77528             if (!arguments.length) return _triggerType;
77529             _triggerType = val;
77530             return editMenu;
77531           };
77532
77533           editMenu.operations = function (val) {
77534             if (!arguments.length) return _operations;
77535             _operations = val;
77536             return editMenu;
77537           };
77538
77539           return utilRebind(editMenu, dispatch$1, 'on');
77540         }
77541
77542         function uiFeatureInfo(context) {
77543           function update(selection) {
77544             var features = context.features();
77545             var stats = features.stats();
77546             var count = 0;
77547             var hiddenList = features.hidden().map(function (k) {
77548               if (stats[k]) {
77549                 count += stats[k];
77550                 return _t('inspector.title_count', {
77551                   title: _t.html('feature.' + k + '.description'),
77552                   count: stats[k]
77553                 });
77554               }
77555
77556               return null;
77557             }).filter(Boolean);
77558             selection.html('');
77559
77560             if (hiddenList.length) {
77561               var tooltipBehavior = uiTooltip().placement('top').title(function () {
77562                 return hiddenList.join('<br/>');
77563               });
77564               selection.append('a').attr('class', 'chip').attr('href', '#').html(_t.html('feature_info.hidden_warning', {
77565                 count: count
77566               })).call(tooltipBehavior).on('click', function (d3_event) {
77567                 tooltipBehavior.hide();
77568                 d3_event.preventDefault(); // open the Map Data pane
77569
77570                 context.ui().togglePanes(context.container().select('.map-panes .map-data-pane'));
77571               });
77572             }
77573
77574             selection.classed('hide', !hiddenList.length);
77575           }
77576
77577           return function (selection) {
77578             update(selection);
77579             context.features().on('change.feature_info', function () {
77580               update(selection);
77581             });
77582           };
77583         }
77584
77585         function uiFlash(context) {
77586           var _flashTimer;
77587
77588           var _duration = 2000;
77589           var _iconName = '#iD-icon-no';
77590           var _iconClass = 'disabled';
77591           var _label = '';
77592
77593           function flash() {
77594             if (_flashTimer) {
77595               _flashTimer.stop();
77596             }
77597
77598             context.container().select('.main-footer-wrap').classed('footer-hide', true).classed('footer-show', false);
77599             context.container().select('.flash-wrap').classed('footer-hide', false).classed('footer-show', true);
77600             var content = context.container().select('.flash-wrap').selectAll('.flash-content').data([0]); // Enter
77601
77602             var contentEnter = content.enter().append('div').attr('class', 'flash-content');
77603             var iconEnter = contentEnter.append('svg').attr('class', 'flash-icon icon').append('g').attr('transform', 'translate(10,10)');
77604             iconEnter.append('circle').attr('r', 9);
77605             iconEnter.append('use').attr('transform', 'translate(-7,-7)').attr('width', '14').attr('height', '14');
77606             contentEnter.append('div').attr('class', 'flash-text'); // Update
77607
77608             content = content.merge(contentEnter);
77609             content.selectAll('.flash-icon').attr('class', 'icon flash-icon ' + (_iconClass || ''));
77610             content.selectAll('.flash-icon use').attr('xlink:href', _iconName);
77611             content.selectAll('.flash-text').attr('class', 'flash-text').html(_label);
77612             _flashTimer = d3_timeout(function () {
77613               _flashTimer = null;
77614               context.container().select('.main-footer-wrap').classed('footer-hide', false).classed('footer-show', true);
77615               context.container().select('.flash-wrap').classed('footer-hide', true).classed('footer-show', false);
77616             }, _duration);
77617             return content;
77618           }
77619
77620           flash.duration = function (_) {
77621             if (!arguments.length) return _duration;
77622             _duration = _;
77623             return flash;
77624           };
77625
77626           flash.label = function (_) {
77627             if (!arguments.length) return _label;
77628             _label = _;
77629             return flash;
77630           };
77631
77632           flash.iconName = function (_) {
77633             if (!arguments.length) return _iconName;
77634             _iconName = _;
77635             return flash;
77636           };
77637
77638           flash.iconClass = function (_) {
77639             if (!arguments.length) return _iconClass;
77640             _iconClass = _;
77641             return flash;
77642           };
77643
77644           return flash;
77645         }
77646
77647         function uiFullScreen(context) {
77648           var element = context.container().node(); // var button = d3_select(null);
77649
77650           function getFullScreenFn() {
77651             if (element.requestFullscreen) {
77652               return element.requestFullscreen;
77653             } else if (element.msRequestFullscreen) {
77654               return element.msRequestFullscreen;
77655             } else if (element.mozRequestFullScreen) {
77656               return element.mozRequestFullScreen;
77657             } else if (element.webkitRequestFullscreen) {
77658               return element.webkitRequestFullscreen;
77659             }
77660           }
77661
77662           function getExitFullScreenFn() {
77663             if (document.exitFullscreen) {
77664               return document.exitFullscreen;
77665             } else if (document.msExitFullscreen) {
77666               return document.msExitFullscreen;
77667             } else if (document.mozCancelFullScreen) {
77668               return document.mozCancelFullScreen;
77669             } else if (document.webkitExitFullscreen) {
77670               return document.webkitExitFullscreen;
77671             }
77672           }
77673
77674           function isFullScreen() {
77675             return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement;
77676           }
77677
77678           function isSupported() {
77679             return !!getFullScreenFn();
77680           }
77681
77682           function fullScreen(d3_event) {
77683             d3_event.preventDefault();
77684
77685             if (!isFullScreen()) {
77686               // button.classed('active', true);
77687               getFullScreenFn().apply(element);
77688             } else {
77689               // button.classed('active', false);
77690               getExitFullScreenFn().apply(document);
77691             }
77692           }
77693
77694           return function () {
77695             // selection) {
77696             if (!isSupported()) return; // button = selection.append('button')
77697             //     .attr('title', t('full_screen'))
77698             //     .on('click', fullScreen)
77699             //     .call(tooltip);
77700             // button.append('span')
77701             //     .attr('class', 'icon full-screen');
77702
77703             var detected = utilDetect();
77704             var keys = detected.os === 'mac' ? [uiCmd('⌃⌘F'), 'f11'] : ['f11'];
77705             context.keybinding().on(keys, fullScreen);
77706           };
77707         }
77708
77709         function uiGeolocate(context) {
77710           var _geolocationOptions = {
77711             // prioritize speed and power usage over precision
77712             enableHighAccuracy: false,
77713             // don't hang indefinitely getting the location
77714             timeout: 6000 // 6sec
77715
77716           };
77717
77718           var _locating = uiLoading(context).message(_t.html('geolocate.locating')).blocking(true);
77719
77720           var _layer = context.layers().layer('geolocate');
77721
77722           var _position;
77723
77724           var _extent;
77725
77726           var _timeoutID;
77727
77728           var _button = select(null);
77729
77730           function click() {
77731             if (context.inIntro()) return;
77732
77733             if (!_layer.enabled() && !_locating.isShown()) {
77734               // This timeout ensures that we still call finish() even if
77735               // the user declines to share their location in Firefox
77736               _timeoutID = setTimeout(error, 10000
77737               /* 10sec */
77738               );
77739               context.container().call(_locating); // get the latest position even if we already have one
77740
77741               navigator.geolocation.getCurrentPosition(success, error, _geolocationOptions);
77742             } else {
77743               _locating.close();
77744
77745               _layer.enabled(null, false);
77746
77747               updateButtonState();
77748             }
77749           }
77750
77751           function zoomTo() {
77752             context.enter(modeBrowse(context));
77753             var map = context.map();
77754
77755             _layer.enabled(_position, true);
77756
77757             updateButtonState();
77758             map.centerZoomEase(_extent.center(), Math.min(20, map.extentZoom(_extent)));
77759           }
77760
77761           function success(geolocation) {
77762             _position = geolocation;
77763             var coords = _position.coords;
77764             _extent = geoExtent([coords.longitude, coords.latitude]).padByMeters(coords.accuracy);
77765             zoomTo();
77766             finish();
77767           }
77768
77769           function error() {
77770             if (_position) {
77771               // use the position from a previous call if we have one
77772               zoomTo();
77773             } else {
77774               context.ui().flash.label(_t.html('geolocate.location_unavailable')).iconName('#iD-icon-geolocate')();
77775             }
77776
77777             finish();
77778           }
77779
77780           function finish() {
77781             _locating.close(); // unblock ui
77782
77783
77784             if (_timeoutID) {
77785               clearTimeout(_timeoutID);
77786             }
77787
77788             _timeoutID = undefined;
77789           }
77790
77791           function updateButtonState() {
77792             _button.classed('active', _layer.enabled());
77793           }
77794
77795           return function (selection) {
77796             if (!navigator.geolocation || !navigator.geolocation.getCurrentPosition) return;
77797             _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')]));
77798             context.keybinding().on(_t('geolocate.key'), click);
77799           };
77800         }
77801
77802         function uiPanelBackground(context) {
77803           var background = context.background();
77804           var _currSourceName = null;
77805           var _metadata = {};
77806           var _metadataKeys = ['zoom', 'vintage', 'source', 'description', 'resolution', 'accuracy'];
77807
77808           var debouncedRedraw = debounce(redraw, 250);
77809
77810           function redraw(selection) {
77811             var source = background.baseLayerSource();
77812             if (!source) return;
77813             var isDG = source.id.match(/^DigitalGlobe/i) !== null;
77814             var sourceLabel = source.label();
77815
77816             if (_currSourceName !== sourceLabel) {
77817               _currSourceName = sourceLabel;
77818               _metadata = {};
77819             }
77820
77821             selection.html('');
77822             var list = selection.append('ul').attr('class', 'background-info');
77823             list.append('li').html(_currSourceName);
77824
77825             _metadataKeys.forEach(function (k) {
77826               // DigitalGlobe vintage is available in raster layers for now.
77827               if (isDG && k === 'vintage') return;
77828               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]);
77829             });
77830
77831             debouncedGetMetadata(selection);
77832             var toggleTiles = context.getDebug('tile') ? 'hide_tiles' : 'show_tiles';
77833             selection.append('a').html(_t.html('info_panels.background.' + toggleTiles)).attr('href', '#').attr('class', 'button button-toggle-tiles').on('click', function (d3_event) {
77834               d3_event.preventDefault();
77835               context.setDebug('tile', !context.getDebug('tile'));
77836               selection.call(redraw);
77837             });
77838
77839             if (isDG) {
77840               var key = source.id + '-vintage';
77841               var sourceVintage = context.background().findSource(key);
77842               var showsVintage = context.background().showsLayer(sourceVintage);
77843               var toggleVintage = showsVintage ? 'hide_vintage' : 'show_vintage';
77844               selection.append('a').html(_t.html('info_panels.background.' + toggleVintage)).attr('href', '#').attr('class', 'button button-toggle-vintage').on('click', function (d3_event) {
77845                 d3_event.preventDefault();
77846                 context.background().toggleOverlayLayer(sourceVintage);
77847                 selection.call(redraw);
77848               });
77849             } // disable if necessary
77850
77851
77852             ['DigitalGlobe-Premium', 'DigitalGlobe-Standard'].forEach(function (layerId) {
77853               if (source.id !== layerId) {
77854                 var key = layerId + '-vintage';
77855                 var sourceVintage = context.background().findSource(key);
77856
77857                 if (context.background().showsLayer(sourceVintage)) {
77858                   context.background().toggleOverlayLayer(sourceVintage);
77859                 }
77860               }
77861             });
77862           }
77863
77864           var debouncedGetMetadata = debounce(getMetadata, 250);
77865
77866           function getMetadata(selection) {
77867             var tile = context.container().select('.layer-background img.tile-center'); // tile near viewport center
77868
77869             if (tile.empty()) return;
77870             var sourceName = _currSourceName;
77871             var d = tile.datum();
77872             var zoom = d && d.length >= 3 && d[2] || Math.floor(context.map().zoom());
77873             var center = context.map().center(); // update zoom
77874
77875             _metadata.zoom = String(zoom);
77876             selection.selectAll('.background-info-list-zoom').classed('hide', false).selectAll('.background-info-span-zoom').html(_metadata.zoom);
77877             if (!d || !d.length >= 3) return;
77878             background.baseLayerSource().getMetadata(center, d, function (err, result) {
77879               if (err || _currSourceName !== sourceName) return; // update vintage
77880
77881               var vintage = result.vintage;
77882               _metadata.vintage = vintage && vintage.range || _t('info_panels.background.unknown');
77883               selection.selectAll('.background-info-list-vintage').classed('hide', false).selectAll('.background-info-span-vintage').html(_metadata.vintage); // update other _metadata
77884
77885               _metadataKeys.forEach(function (k) {
77886                 if (k === 'zoom' || k === 'vintage') return; // done already
77887
77888                 var val = result[k];
77889                 _metadata[k] = val;
77890                 selection.selectAll('.background-info-list-' + k).classed('hide', !val).selectAll('.background-info-span-' + k).html(val);
77891               });
77892             });
77893           }
77894
77895           var panel = function panel(selection) {
77896             selection.call(redraw);
77897             context.map().on('drawn.info-background', function () {
77898               selection.call(debouncedRedraw);
77899             }).on('move.info-background', function () {
77900               selection.call(debouncedGetMetadata);
77901             });
77902           };
77903
77904           panel.off = function () {
77905             context.map().on('drawn.info-background', null).on('move.info-background', null);
77906           };
77907
77908           panel.id = 'background';
77909           panel.label = _t.html('info_panels.background.title');
77910           panel.key = _t('info_panels.background.key');
77911           return panel;
77912         }
77913
77914         function uiPanelHistory(context) {
77915           var osm;
77916
77917           function displayTimestamp(timestamp) {
77918             if (!timestamp) return _t('info_panels.history.unknown');
77919             var options = {
77920               day: 'numeric',
77921               month: 'short',
77922               year: 'numeric',
77923               hour: 'numeric',
77924               minute: 'numeric',
77925               second: 'numeric'
77926             };
77927             var d = new Date(timestamp);
77928             if (isNaN(d.getTime())) return _t('info_panels.history.unknown');
77929             return d.toLocaleString(_mainLocalizer.localeCode(), options);
77930           }
77931
77932           function displayUser(selection, userName) {
77933             if (!userName) {
77934               selection.append('span').html(_t.html('info_panels.history.unknown'));
77935               return;
77936             }
77937
77938             selection.append('span').attr('class', 'user-name').html(userName);
77939             var links = selection.append('div').attr('class', 'links');
77940
77941             if (osm) {
77942               links.append('a').attr('class', 'user-osm-link').attr('href', osm.userURL(userName)).attr('target', '_blank').html('OSM');
77943             }
77944
77945             links.append('a').attr('class', 'user-hdyc-link').attr('href', 'https://hdyc.neis-one.org/?' + userName).attr('target', '_blank').attr('tabindex', -1).html('HDYC');
77946           }
77947
77948           function displayChangeset(selection, changeset) {
77949             if (!changeset) {
77950               selection.append('span').html(_t.html('info_panels.history.unknown'));
77951               return;
77952             }
77953
77954             selection.append('span').attr('class', 'changeset-id').html(changeset);
77955             var links = selection.append('div').attr('class', 'links');
77956
77957             if (osm) {
77958               links.append('a').attr('class', 'changeset-osm-link').attr('href', osm.changesetURL(changeset)).attr('target', '_blank').html('OSM');
77959             }
77960
77961             links.append('a').attr('class', 'changeset-osmcha-link').attr('href', 'https://osmcha.org/changesets/' + changeset).attr('target', '_blank').html('OSMCha');
77962             links.append('a').attr('class', 'changeset-achavi-link').attr('href', 'https://overpass-api.de/achavi/?changeset=' + changeset).attr('target', '_blank').html('Achavi');
77963           }
77964
77965           function redraw(selection) {
77966             var selectedNoteID = context.selectedNoteID();
77967             osm = context.connection();
77968             var selected, note, entity;
77969
77970             if (selectedNoteID && osm) {
77971               // selected 1 note
77972               selected = [_t('note.note') + ' ' + selectedNoteID];
77973               note = osm.getNote(selectedNoteID);
77974             } else {
77975               // selected 1..n entities
77976               selected = context.selectedIDs().filter(function (e) {
77977                 return context.hasEntity(e);
77978               });
77979
77980               if (selected.length) {
77981                 entity = context.entity(selected[0]);
77982               }
77983             }
77984
77985             var singular = selected.length === 1 ? selected[0] : null;
77986             selection.html('');
77987             selection.append('h4').attr('class', 'history-heading').html(singular || _t.html('info_panels.selected', {
77988               n: selected.length
77989             }));
77990             if (!singular) return;
77991
77992             if (entity) {
77993               selection.call(redrawEntity, entity);
77994             } else if (note) {
77995               selection.call(redrawNote, note);
77996             }
77997           }
77998
77999           function redrawNote(selection, note) {
78000             if (!note || note.isNew()) {
78001               selection.append('div').html(_t.html('info_panels.history.note_no_history'));
78002               return;
78003             }
78004
78005             var list = selection.append('ul');
78006             list.append('li').html(_t.html('info_panels.history.note_comments') + ':').append('span').html(note.comments.length);
78007
78008             if (note.comments.length) {
78009               list.append('li').html(_t.html('info_panels.history.note_created_date') + ':').append('span').html(displayTimestamp(note.comments[0].date));
78010               list.append('li').html(_t.html('info_panels.history.note_created_user') + ':').call(displayUser, note.comments[0].user);
78011             }
78012
78013             if (osm) {
78014               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'));
78015             }
78016           }
78017
78018           function redrawEntity(selection, entity) {
78019             if (!entity || entity.isNew()) {
78020               selection.append('div').html(_t.html('info_panels.history.no_history'));
78021               return;
78022             }
78023
78024             var links = selection.append('div').attr('class', 'links');
78025
78026             if (osm) {
78027               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');
78028             }
78029
78030             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');
78031             var list = selection.append('ul');
78032             list.append('li').html(_t.html('info_panels.history.version') + ':').append('span').html(entity.version);
78033             list.append('li').html(_t.html('info_panels.history.last_edit') + ':').append('span').html(displayTimestamp(entity.timestamp));
78034             list.append('li').html(_t.html('info_panels.history.edited_by') + ':').call(displayUser, entity.user);
78035             list.append('li').html(_t.html('info_panels.history.changeset') + ':').call(displayChangeset, entity.changeset);
78036           }
78037
78038           var panel = function panel(selection) {
78039             selection.call(redraw);
78040             context.map().on('drawn.info-history', function () {
78041               selection.call(redraw);
78042             });
78043             context.on('enter.info-history', function () {
78044               selection.call(redraw);
78045             });
78046           };
78047
78048           panel.off = function () {
78049             context.map().on('drawn.info-history', null);
78050             context.on('enter.info-history', null);
78051           };
78052
78053           panel.id = 'history';
78054           panel.label = _t.html('info_panels.history.title');
78055           panel.key = _t('info_panels.history.key');
78056           return panel;
78057         }
78058
78059         var OSM_PRECISION = 7;
78060         /**
78061          * Returns a localized representation of the given length measurement.
78062          *
78063          * @param {Number} m area in meters
78064          * @param {Boolean} isImperial true for U.S. customary units; false for metric
78065          */
78066
78067         function displayLength(m, isImperial) {
78068           var d = m * (isImperial ? 3.28084 : 1);
78069           var unit;
78070
78071           if (isImperial) {
78072             if (d >= 5280) {
78073               d /= 5280;
78074               unit = 'miles';
78075             } else {
78076               unit = 'feet';
78077             }
78078           } else {
78079             if (d >= 1000) {
78080               d /= 1000;
78081               unit = 'kilometers';
78082             } else {
78083               unit = 'meters';
78084             }
78085           }
78086
78087           return _t('units.' + unit, {
78088             quantity: d.toLocaleString(_mainLocalizer.localeCode(), {
78089               maximumSignificantDigits: 4
78090             })
78091           });
78092         }
78093         /**
78094          * Returns a localized representation of the given area measurement.
78095          *
78096          * @param {Number} m2 area in square meters
78097          * @param {Boolean} isImperial true for U.S. customary units; false for metric
78098          */
78099
78100         function displayArea(m2, isImperial) {
78101           var locale = _mainLocalizer.localeCode();
78102           var d = m2 * (isImperial ? 10.7639111056 : 1);
78103           var d1, d2, area;
78104           var unit1 = '';
78105           var unit2 = '';
78106
78107           if (isImperial) {
78108             if (d >= 6969600) {
78109               // > 0.25mi² show mi²
78110               d1 = d / 27878400;
78111               unit1 = 'square_miles';
78112             } else {
78113               d1 = d;
78114               unit1 = 'square_feet';
78115             }
78116
78117             if (d > 4356 && d < 43560000) {
78118               // 0.1 - 1000 acres
78119               d2 = d / 43560;
78120               unit2 = 'acres';
78121             }
78122           } else {
78123             if (d >= 250000) {
78124               // > 0.25km² show km²
78125               d1 = d / 1000000;
78126               unit1 = 'square_kilometers';
78127             } else {
78128               d1 = d;
78129               unit1 = 'square_meters';
78130             }
78131
78132             if (d > 1000 && d < 10000000) {
78133               // 0.1 - 1000 hectares
78134               d2 = d / 10000;
78135               unit2 = 'hectares';
78136             }
78137           }
78138
78139           area = _t('units.' + unit1, {
78140             quantity: d1.toLocaleString(locale, {
78141               maximumSignificantDigits: 4
78142             })
78143           });
78144
78145           if (d2) {
78146             return _t('units.area_pair', {
78147               area1: area,
78148               area2: _t('units.' + unit2, {
78149                 quantity: d2.toLocaleString(locale, {
78150                   maximumSignificantDigits: 2
78151                 })
78152               })
78153             });
78154           } else {
78155             return area;
78156           }
78157         }
78158
78159         function wrap$2(x, min, max) {
78160           var d = max - min;
78161           return ((x - min) % d + d) % d + min;
78162         }
78163
78164         function clamp$1(x, min, max) {
78165           return Math.max(min, Math.min(x, max));
78166         }
78167
78168         function displayCoordinate(deg, pos, neg) {
78169           var locale = _mainLocalizer.localeCode();
78170           var min = (Math.abs(deg) - Math.floor(Math.abs(deg))) * 60;
78171           var sec = (min - Math.floor(min)) * 60;
78172           var displayDegrees = _t('units.arcdegrees', {
78173             quantity: Math.floor(Math.abs(deg)).toLocaleString(locale)
78174           });
78175           var displayCoordinate;
78176
78177           if (Math.floor(sec) > 0) {
78178             displayCoordinate = displayDegrees + _t('units.arcminutes', {
78179               quantity: Math.floor(min).toLocaleString(locale)
78180             }) + _t('units.arcseconds', {
78181               quantity: Math.round(sec).toLocaleString(locale)
78182             });
78183           } else if (Math.floor(min) > 0) {
78184             displayCoordinate = displayDegrees + _t('units.arcminutes', {
78185               quantity: Math.round(min).toLocaleString(locale)
78186             });
78187           } else {
78188             displayCoordinate = _t('units.arcdegrees', {
78189               quantity: Math.round(Math.abs(deg)).toLocaleString(locale)
78190             });
78191           }
78192
78193           if (deg === 0) {
78194             return displayCoordinate;
78195           } else {
78196             return _t('units.coordinate', {
78197               coordinate: displayCoordinate,
78198               direction: _t('units.' + (deg > 0 ? pos : neg))
78199             });
78200           }
78201         }
78202         /**
78203          * Returns given coordinate pair in degree-minute-second format.
78204          *
78205          * @param {Array<Number>} coord longitude and latitude
78206          */
78207
78208
78209         function dmsCoordinatePair(coord) {
78210           return _t('units.coordinate_pair', {
78211             latitude: displayCoordinate(clamp$1(coord[1], -90, 90), 'north', 'south'),
78212             longitude: displayCoordinate(wrap$2(coord[0], -180, 180), 'east', 'west')
78213           });
78214         }
78215         /**
78216          * Returns the given coordinate pair in decimal format.
78217          * note: unlocalized to avoid comma ambiguity - see #4765
78218          *
78219          * @param {Array<Number>} coord longitude and latitude
78220          */
78221
78222         function decimalCoordinatePair(coord) {
78223           return _t('units.coordinate_pair', {
78224             latitude: clamp$1(coord[1], -90, 90).toFixed(OSM_PRECISION),
78225             longitude: wrap$2(coord[0], -180, 180).toFixed(OSM_PRECISION)
78226           });
78227         }
78228
78229         function uiPanelLocation(context) {
78230           var currLocation = '';
78231
78232           function redraw(selection) {
78233             selection.html('');
78234             var list = selection.append('ul'); // Mouse coordinates
78235
78236             var coord = context.map().mouseCoordinates();
78237
78238             if (coord.some(isNaN)) {
78239               coord = context.map().center();
78240             }
78241
78242             list.append('li').html(dmsCoordinatePair(coord)).append('li').html(decimalCoordinatePair(coord)); // Location Info
78243
78244             selection.append('div').attr('class', 'location-info').html(currLocation || ' ');
78245             debouncedGetLocation(selection, coord);
78246           }
78247
78248           var debouncedGetLocation = debounce(getLocation, 250);
78249
78250           function getLocation(selection, coord) {
78251             if (!services.geocoder) {
78252               currLocation = _t('info_panels.location.unknown_location');
78253               selection.selectAll('.location-info').html(currLocation);
78254             } else {
78255               services.geocoder.reverse(coord, function (err, result) {
78256                 currLocation = result ? result.display_name : _t('info_panels.location.unknown_location');
78257                 selection.selectAll('.location-info').html(currLocation);
78258               });
78259             }
78260           }
78261
78262           var panel = function panel(selection) {
78263             selection.call(redraw);
78264             context.surface().on(('PointerEvent' in window ? 'pointer' : 'mouse') + 'move.info-location', function () {
78265               selection.call(redraw);
78266             });
78267           };
78268
78269           panel.off = function () {
78270             context.surface().on('.info-location', null);
78271           };
78272
78273           panel.id = 'location';
78274           panel.label = _t.html('info_panels.location.title');
78275           panel.key = _t('info_panels.location.key');
78276           return panel;
78277         }
78278
78279         function uiPanelMeasurement(context) {
78280           function radiansToMeters(r) {
78281             // using WGS84 authalic radius (6371007.1809 m)
78282             return r * 6371007.1809;
78283           }
78284
78285           function steradiansToSqmeters(r) {
78286             // http://gis.stackexchange.com/a/124857/40446
78287             return r / (4 * Math.PI) * 510065621724000;
78288           }
78289
78290           function toLineString(feature) {
78291             if (feature.type === 'LineString') return feature;
78292             var result = {
78293               type: 'LineString',
78294               coordinates: []
78295             };
78296
78297             if (feature.type === 'Polygon') {
78298               result.coordinates = feature.coordinates[0];
78299             } else if (feature.type === 'MultiPolygon') {
78300               result.coordinates = feature.coordinates[0][0];
78301             }
78302
78303             return result;
78304           }
78305
78306           var _isImperial = !_mainLocalizer.usesMetric();
78307
78308           function redraw(selection) {
78309             var graph = context.graph();
78310             var selectedNoteID = context.selectedNoteID();
78311             var osm = services.osm;
78312             var localeCode = _mainLocalizer.localeCode();
78313             var heading;
78314             var center, location, centroid;
78315             var closed, geometry;
78316             var totalNodeCount,
78317                 length = 0,
78318                 area = 0,
78319                 distance;
78320
78321             if (selectedNoteID && osm) {
78322               // selected 1 note
78323               var note = osm.getNote(selectedNoteID);
78324               heading = _t('note.note') + ' ' + selectedNoteID;
78325               location = note.loc;
78326               geometry = 'note';
78327             } else {
78328               // selected 1..n entities
78329               var selectedIDs = context.selectedIDs().filter(function (id) {
78330                 return context.hasEntity(id);
78331               });
78332               var selected = selectedIDs.map(function (id) {
78333                 return context.entity(id);
78334               });
78335               heading = selected.length === 1 ? selected[0].id : _t('info_panels.selected', {
78336                 n: selected.length
78337               });
78338
78339               if (selected.length) {
78340                 var extent = geoExtent();
78341
78342                 for (var i in selected) {
78343                   var entity = selected[i];
78344
78345                   extent._extend(entity.extent(graph));
78346
78347                   geometry = entity.geometry(graph);
78348
78349                   if (geometry === 'line' || geometry === 'area') {
78350                     closed = entity.type === 'relation' || entity.isClosed() && !entity.isDegenerate();
78351                     var feature = entity.asGeoJSON(graph);
78352                     length += radiansToMeters(d3_geoLength(toLineString(feature))); // d3_geoCentroid is wrong for counterclockwise-wound polygons, so wind them clockwise
78353
78354                     centroid = d3_geoCentroid(geojsonRewind(Object.assign({}, feature), true));
78355
78356                     if (closed) {
78357                       area += steradiansToSqmeters(entity.area(graph));
78358                     }
78359                   }
78360                 }
78361
78362                 if (selected.length > 1) {
78363                   geometry = null;
78364                   closed = null;
78365                   centroid = null;
78366                 }
78367
78368                 if (selected.length === 2 && selected[0].type === 'node' && selected[1].type === 'node') {
78369                   distance = geoSphericalDistance(selected[0].loc, selected[1].loc);
78370                 }
78371
78372                 if (selected.length === 1 && selected[0].type === 'node') {
78373                   location = selected[0].loc;
78374                 } else {
78375                   totalNodeCount = utilGetAllNodes(selectedIDs, context.graph()).length;
78376                 }
78377
78378                 if (!location && !centroid) {
78379                   center = extent.center();
78380                 }
78381               }
78382             }
78383
78384             selection.html('');
78385
78386             if (heading) {
78387               selection.append('h4').attr('class', 'measurement-heading').html(heading);
78388             }
78389
78390             var list = selection.append('ul');
78391             var coordItem;
78392
78393             if (geometry) {
78394               list.append('li').html(_t.html('info_panels.measurement.geometry') + ':').append('span').html(closed ? _t('info_panels.measurement.closed_' + geometry) : _t('geometry.' + geometry));
78395             }
78396
78397             if (totalNodeCount) {
78398               list.append('li').html(_t.html('info_panels.measurement.node_count') + ':').append('span').html(totalNodeCount.toLocaleString(localeCode));
78399             }
78400
78401             if (area) {
78402               list.append('li').html(_t.html('info_panels.measurement.area') + ':').append('span').html(displayArea(area, _isImperial));
78403             }
78404
78405             if (length) {
78406               list.append('li').html(_t.html('info_panels.measurement.' + (closed ? 'perimeter' : 'length')) + ':').append('span').html(displayLength(length, _isImperial));
78407             }
78408
78409             if (typeof distance === 'number') {
78410               list.append('li').html(_t.html('info_panels.measurement.distance') + ':').append('span').html(displayLength(distance, _isImperial));
78411             }
78412
78413             if (location) {
78414               coordItem = list.append('li').html(_t.html('info_panels.measurement.location') + ':');
78415               coordItem.append('span').html(dmsCoordinatePair(location));
78416               coordItem.append('span').html(decimalCoordinatePair(location));
78417             }
78418
78419             if (centroid) {
78420               coordItem = list.append('li').html(_t.html('info_panels.measurement.centroid') + ':');
78421               coordItem.append('span').html(dmsCoordinatePair(centroid));
78422               coordItem.append('span').html(decimalCoordinatePair(centroid));
78423             }
78424
78425             if (center) {
78426               coordItem = list.append('li').html(_t.html('info_panels.measurement.center') + ':');
78427               coordItem.append('span').html(dmsCoordinatePair(center));
78428               coordItem.append('span').html(decimalCoordinatePair(center));
78429             }
78430
78431             if (length || area || typeof distance === 'number') {
78432               var toggle = _isImperial ? 'imperial' : 'metric';
78433               selection.append('a').html(_t.html('info_panels.measurement.' + toggle)).attr('href', '#').attr('class', 'button button-toggle-units').on('click', function (d3_event) {
78434                 d3_event.preventDefault();
78435                 _isImperial = !_isImperial;
78436                 selection.call(redraw);
78437               });
78438             }
78439           }
78440
78441           var panel = function panel(selection) {
78442             selection.call(redraw);
78443             context.map().on('drawn.info-measurement', function () {
78444               selection.call(redraw);
78445             });
78446             context.on('enter.info-measurement', function () {
78447               selection.call(redraw);
78448             });
78449           };
78450
78451           panel.off = function () {
78452             context.map().on('drawn.info-measurement', null);
78453             context.on('enter.info-measurement', null);
78454           };
78455
78456           panel.id = 'measurement';
78457           panel.label = _t.html('info_panels.measurement.title');
78458           panel.key = _t('info_panels.measurement.key');
78459           return panel;
78460         }
78461
78462         var uiInfoPanels = {
78463           background: uiPanelBackground,
78464           history: uiPanelHistory,
78465           location: uiPanelLocation,
78466           measurement: uiPanelMeasurement
78467         };
78468
78469         function uiInfo(context) {
78470           var ids = Object.keys(uiInfoPanels);
78471           var wasActive = ['measurement'];
78472           var panels = {};
78473           var active = {}; // create panels
78474
78475           ids.forEach(function (k) {
78476             if (!panels[k]) {
78477               panels[k] = uiInfoPanels[k](context);
78478               active[k] = false;
78479             }
78480           });
78481
78482           function info(selection) {
78483             function redraw() {
78484               var activeids = ids.filter(function (k) {
78485                 return active[k];
78486               }).sort();
78487               var containers = infoPanels.selectAll('.panel-container').data(activeids, function (k) {
78488                 return k;
78489               });
78490               containers.exit().style('opacity', 1).transition().duration(200).style('opacity', 0).on('end', function (d) {
78491                 select(this).call(panels[d].off).remove();
78492               });
78493               var enter = containers.enter().append('div').attr('class', function (d) {
78494                 return 'fillD2 panel-container panel-container-' + d;
78495               });
78496               enter.style('opacity', 0).transition().duration(200).style('opacity', 1);
78497               var title = enter.append('div').attr('class', 'panel-title fillD2');
78498               title.append('h3').html(function (d) {
78499                 return panels[d].label;
78500               });
78501               title.append('button').attr('class', 'close').on('click', function (d3_event, d) {
78502                 d3_event.stopImmediatePropagation();
78503                 d3_event.preventDefault();
78504                 info.toggle(d);
78505               }).call(svgIcon('#iD-icon-close'));
78506               enter.append('div').attr('class', function (d) {
78507                 return 'panel-content panel-content-' + d;
78508               }); // redraw the panels
78509
78510               infoPanels.selectAll('.panel-content').each(function (d) {
78511                 select(this).call(panels[d]);
78512               });
78513             }
78514
78515             info.toggle = function (which) {
78516               var activeids = ids.filter(function (k) {
78517                 return active[k];
78518               });
78519
78520               if (which) {
78521                 // toggle one
78522                 active[which] = !active[which];
78523
78524                 if (activeids.length === 1 && activeids[0] === which) {
78525                   // none active anymore
78526                   wasActive = [which];
78527                 }
78528
78529                 context.container().select('.' + which + '-panel-toggle-item').classed('active', active[which]).select('input').property('checked', active[which]);
78530               } else {
78531                 // toggle all
78532                 if (activeids.length) {
78533                   wasActive = activeids;
78534                   activeids.forEach(function (k) {
78535                     active[k] = false;
78536                   });
78537                 } else {
78538                   wasActive.forEach(function (k) {
78539                     active[k] = true;
78540                   });
78541                 }
78542               }
78543
78544               redraw();
78545             };
78546
78547             var infoPanels = selection.selectAll('.info-panels').data([0]);
78548             infoPanels = infoPanels.enter().append('div').attr('class', 'info-panels').merge(infoPanels);
78549             redraw();
78550             context.keybinding().on(uiCmd('⌘' + _t('info_panels.key')), function (d3_event) {
78551               d3_event.stopImmediatePropagation();
78552               d3_event.preventDefault();
78553               info.toggle();
78554             });
78555             ids.forEach(function (k) {
78556               var key = _t('info_panels.' + k + '.key', {
78557                 "default": null
78558               });
78559               if (!key) return;
78560               context.keybinding().on(uiCmd('⌘⇧' + key), function (d3_event) {
78561                 d3_event.stopImmediatePropagation();
78562                 d3_event.preventDefault();
78563                 info.toggle(k);
78564               });
78565             });
78566           }
78567
78568           return info;
78569         }
78570
78571         function pointBox(loc, context) {
78572           var rect = context.surfaceRect();
78573           var point = context.curtainProjection(loc);
78574           return {
78575             left: point[0] + rect.left - 40,
78576             top: point[1] + rect.top - 60,
78577             width: 80,
78578             height: 90
78579           };
78580         }
78581         function pad(locOrBox, padding, context) {
78582           var box;
78583
78584           if (locOrBox instanceof Array) {
78585             var rect = context.surfaceRect();
78586             var point = context.curtainProjection(locOrBox);
78587             box = {
78588               left: point[0] + rect.left,
78589               top: point[1] + rect.top
78590             };
78591           } else {
78592             box = locOrBox;
78593           }
78594
78595           return {
78596             left: box.left - padding,
78597             top: box.top - padding,
78598             width: (box.width || 0) + 2 * padding,
78599             height: (box.width || 0) + 2 * padding
78600           };
78601         }
78602         function icon(name, svgklass, useklass) {
78603           return '<svg class="icon ' + (svgklass || '') + '">' + '<use xlink:href="' + name + '"' + (useklass ? ' class="' + useklass + '"' : '') + '></use></svg>';
78604         }
78605         var helpStringReplacements; // Returns the localized HTML element for `id` with a standardized set of icon, key, and
78606         // label replacements suitable for tutorials and documentation. Optionally supplemented
78607         // with custom `replacements`
78608
78609         function helpHtml(id, replacements) {
78610           // only load these the first time
78611           if (!helpStringReplacements) helpStringReplacements = {
78612             // insert icons corresponding to various UI elements
78613             point_icon: icon('#iD-icon-point', 'inline'),
78614             line_icon: icon('#iD-icon-line', 'inline'),
78615             area_icon: icon('#iD-icon-area', 'inline'),
78616             note_icon: icon('#iD-icon-note', 'inline add-note'),
78617             plus: icon('#iD-icon-plus', 'inline'),
78618             minus: icon('#iD-icon-minus', 'inline'),
78619             layers_icon: icon('#iD-icon-layers', 'inline'),
78620             data_icon: icon('#iD-icon-data', 'inline'),
78621             inspect: icon('#iD-icon-inspect', 'inline'),
78622             help_icon: icon('#iD-icon-help', 'inline'),
78623             undo_icon: icon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-redo' : '#iD-icon-undo', 'inline'),
78624             redo_icon: icon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-undo' : '#iD-icon-redo', 'inline'),
78625             save_icon: icon('#iD-icon-save', 'inline'),
78626             // operation icons
78627             circularize_icon: icon('#iD-operation-circularize', 'inline operation'),
78628             continue_icon: icon('#iD-operation-continue', 'inline operation'),
78629             copy_icon: icon('#iD-operation-copy', 'inline operation'),
78630             delete_icon: icon('#iD-operation-delete', 'inline operation'),
78631             disconnect_icon: icon('#iD-operation-disconnect', 'inline operation'),
78632             downgrade_icon: icon('#iD-operation-downgrade', 'inline operation'),
78633             extract_icon: icon('#iD-operation-extract', 'inline operation'),
78634             merge_icon: icon('#iD-operation-merge', 'inline operation'),
78635             move_icon: icon('#iD-operation-move', 'inline operation'),
78636             orthogonalize_icon: icon('#iD-operation-orthogonalize', 'inline operation'),
78637             paste_icon: icon('#iD-operation-paste', 'inline operation'),
78638             reflect_long_icon: icon('#iD-operation-reflect-long', 'inline operation'),
78639             reflect_short_icon: icon('#iD-operation-reflect-short', 'inline operation'),
78640             reverse_icon: icon('#iD-operation-reverse', 'inline operation'),
78641             rotate_icon: icon('#iD-operation-rotate', 'inline operation'),
78642             split_icon: icon('#iD-operation-split', 'inline operation'),
78643             straighten_icon: icon('#iD-operation-straighten', 'inline operation'),
78644             // interaction icons
78645             leftclick: icon('#iD-walkthrough-mouse-left', 'inline operation'),
78646             rightclick: icon('#iD-walkthrough-mouse-right', 'inline operation'),
78647             mousewheel_icon: icon('#iD-walkthrough-mousewheel', 'inline operation'),
78648             tap_icon: icon('#iD-walkthrough-tap', 'inline operation'),
78649             doubletap_icon: icon('#iD-walkthrough-doubletap', 'inline operation'),
78650             longpress_icon: icon('#iD-walkthrough-longpress', 'inline operation'),
78651             touchdrag_icon: icon('#iD-walkthrough-touchdrag', 'inline operation'),
78652             pinch_icon: icon('#iD-walkthrough-pinch-apart', 'inline operation'),
78653             // insert keys; may be localized and platform-dependent
78654             shift: uiCmd.display('⇧'),
78655             alt: uiCmd.display('⌥'),
78656             "return": uiCmd.display('↵'),
78657             esc: _t.html('shortcuts.key.esc'),
78658             space: _t.html('shortcuts.key.space'),
78659             add_note_key: _t.html('modes.add_note.key'),
78660             help_key: _t.html('help.key'),
78661             shortcuts_key: _t.html('shortcuts.toggle.key'),
78662             // reference localized UI labels directly so that they'll always match
78663             save: _t.html('save.title'),
78664             undo: _t.html('undo.title'),
78665             redo: _t.html('redo.title'),
78666             upload: _t.html('commit.save'),
78667             point: _t.html('modes.add_point.title'),
78668             line: _t.html('modes.add_line.title'),
78669             area: _t.html('modes.add_area.title'),
78670             note: _t.html('modes.add_note.label'),
78671             circularize: _t.html('operations.circularize.title'),
78672             "continue": _t.html('operations.continue.title'),
78673             copy: _t.html('operations.copy.title'),
78674             "delete": _t.html('operations.delete.title'),
78675             disconnect: _t.html('operations.disconnect.title'),
78676             downgrade: _t.html('operations.downgrade.title'),
78677             extract: _t.html('operations.extract.title'),
78678             merge: _t.html('operations.merge.title'),
78679             move: _t.html('operations.move.title'),
78680             orthogonalize: _t.html('operations.orthogonalize.title'),
78681             paste: _t.html('operations.paste.title'),
78682             reflect_long: _t.html('operations.reflect.title.long'),
78683             reflect_short: _t.html('operations.reflect.title.short'),
78684             reverse: _t.html('operations.reverse.title'),
78685             rotate: _t.html('operations.rotate.title'),
78686             split: _t.html('operations.split.title'),
78687             straighten: _t.html('operations.straighten.title'),
78688             map_data: _t.html('map_data.title'),
78689             osm_notes: _t.html('map_data.layers.notes.title'),
78690             fields: _t.html('inspector.fields'),
78691             tags: _t.html('inspector.tags'),
78692             relations: _t.html('inspector.relations'),
78693             new_relation: _t.html('inspector.new_relation'),
78694             turn_restrictions: _t.html('presets.fields.restrictions.label'),
78695             background_settings: _t.html('background.description'),
78696             imagery_offset: _t.html('background.fix_misalignment'),
78697             start_the_walkthrough: _t.html('splash.walkthrough'),
78698             help: _t.html('help.title'),
78699             ok: _t.html('intro.ok')
78700           };
78701           var reps;
78702
78703           if (replacements) {
78704             reps = Object.assign(replacements, helpStringReplacements);
78705           } else {
78706             reps = helpStringReplacements;
78707           }
78708
78709           return _t.html(id, reps) // use keyboard key styling for shortcuts
78710           .replace(/\`(.*?)\`/g, '<kbd>$1</kbd>');
78711         }
78712
78713         function slugify(text) {
78714           return text.toString().toLowerCase().replace(/\s+/g, '-') // Replace spaces with -
78715           .replace(/[^\w\-]+/g, '') // Remove all non-word chars
78716           .replace(/\-\-+/g, '-') // Replace multiple - with single -
78717           .replace(/^-+/, '') // Trim - from start of text
78718           .replace(/-+$/, ''); // Trim - from end of text
78719         } // console warning for missing walkthrough names
78720
78721
78722         var missingStrings = {};
78723
78724         function checkKey(key, text) {
78725           if (_t(key, {
78726             "default": undefined
78727           }) === undefined) {
78728             if (missingStrings.hasOwnProperty(key)) return; // warn once
78729
78730             missingStrings[key] = text;
78731             var missing = key + ': ' + text;
78732             if (typeof console !== 'undefined') console.log(missing); // eslint-disable-line
78733           }
78734         }
78735
78736         function localize(obj) {
78737           var key; // Assign name if entity has one..
78738
78739           var name = obj.tags && obj.tags.name;
78740
78741           if (name) {
78742             key = 'intro.graph.name.' + slugify(name);
78743             obj.tags.name = _t(key, {
78744               "default": name
78745             });
78746             checkKey(key, name);
78747           } // Assign street name if entity has one..
78748
78749
78750           var street = obj.tags && obj.tags['addr:street'];
78751
78752           if (street) {
78753             key = 'intro.graph.name.' + slugify(street);
78754             obj.tags['addr:street'] = _t(key, {
78755               "default": street
78756             });
78757             checkKey(key, street); // Add address details common across walkthrough..
78758
78759             var addrTags = ['block_number', 'city', 'county', 'district', 'hamlet', 'neighbourhood', 'postcode', 'province', 'quarter', 'state', 'subdistrict', 'suburb'];
78760             addrTags.forEach(function (k) {
78761               var key = 'intro.graph.' + k;
78762               var tag = 'addr:' + k;
78763               var val = obj.tags && obj.tags[tag];
78764               var str = _t(key, {
78765                 "default": val
78766               });
78767
78768               if (str) {
78769                 if (str.match(/^<.*>$/) !== null) {
78770                   delete obj.tags[tag];
78771                 } else {
78772                   obj.tags[tag] = str;
78773                 }
78774               }
78775             });
78776           }
78777
78778           return obj;
78779         } // Used to detect squareness.. some duplicataion of code from actionOrthogonalize.
78780
78781         function isMostlySquare(points) {
78782           // note: uses 15 here instead of the 12 from actionOrthogonalize because
78783           // actionOrthogonalize can actually straighten some larger angles as it iterates
78784           var threshold = 15; // degrees within right or straight
78785
78786           var lowerBound = Math.cos((90 - threshold) * Math.PI / 180); // near right
78787
78788           var upperBound = Math.cos(threshold * Math.PI / 180); // near straight
78789
78790           for (var i = 0; i < points.length; i++) {
78791             var a = points[(i - 1 + points.length) % points.length];
78792             var origin = points[i];
78793             var b = points[(i + 1) % points.length];
78794             var dotp = geoVecNormalizedDot(a, b, origin);
78795             var mag = Math.abs(dotp);
78796
78797             if (mag > lowerBound && mag < upperBound) {
78798               return false;
78799             }
78800           }
78801
78802           return true;
78803         }
78804         function selectMenuItem(context, operation) {
78805           return context.container().select('.edit-menu .edit-menu-item-' + operation);
78806         }
78807         function transitionTime(point1, point2) {
78808           var distance = geoSphericalDistance(point1, point2);
78809           if (distance === 0) return 0;else if (distance < 80) return 500;else return 1000;
78810         }
78811
78812         function uiCurtain(containerNode) {
78813           var surface = select(null),
78814               tooltip = select(null),
78815               darkness = select(null);
78816
78817           function curtain(selection) {
78818             surface = selection.append('svg').attr('class', 'curtain').style('top', 0).style('left', 0);
78819             darkness = surface.append('path').attr('x', 0).attr('y', 0).attr('class', 'curtain-darkness');
78820             select(window).on('resize.curtain', resize);
78821             tooltip = selection.append('div').attr('class', 'tooltip');
78822             tooltip.append('div').attr('class', 'popover-arrow');
78823             tooltip.append('div').attr('class', 'popover-inner');
78824             resize();
78825
78826             function resize() {
78827               surface.attr('width', containerNode.clientWidth).attr('height', containerNode.clientHeight);
78828               curtain.cut(darkness.datum());
78829             }
78830           }
78831           /**
78832            * Reveal cuts the curtain to highlight the given box,
78833            * and shows a tooltip with instructions next to the box.
78834            *
78835            * @param  {String|ClientRect} [box]   box used to cut the curtain
78836            * @param  {String}    [text]          text for a tooltip
78837            * @param  {Object}    [options]
78838            * @param  {string}    [options.tooltipClass]    optional class to add to the tooltip
78839            * @param  {integer}   [options.duration]        transition time in milliseconds
78840            * @param  {string}    [options.buttonText]      if set, create a button with this text label
78841            * @param  {function}  [options.buttonCallback]  if set, the callback for the button
78842            * @param  {function}  [options.padding]         extra margin in px to put around bbox
78843            * @param  {String|ClientRect} [options.tooltipBox]  box for tooltip position, if different from box for the curtain
78844            */
78845
78846
78847           curtain.reveal = function (box, html, options) {
78848             options = options || {};
78849
78850             if (typeof box === 'string') {
78851               box = select(box).node();
78852             }
78853
78854             if (box && box.getBoundingClientRect) {
78855               box = copyBox(box.getBoundingClientRect());
78856               var containerRect = containerNode.getBoundingClientRect();
78857               box.top -= containerRect.top;
78858               box.left -= containerRect.left;
78859             }
78860
78861             if (box && options.padding) {
78862               box.top -= options.padding;
78863               box.left -= options.padding;
78864               box.bottom += options.padding;
78865               box.right += options.padding;
78866               box.height += options.padding * 2;
78867               box.width += options.padding * 2;
78868             }
78869
78870             var tooltipBox;
78871
78872             if (options.tooltipBox) {
78873               tooltipBox = options.tooltipBox;
78874
78875               if (typeof tooltipBox === 'string') {
78876                 tooltipBox = select(tooltipBox).node();
78877               }
78878
78879               if (tooltipBox && tooltipBox.getBoundingClientRect) {
78880                 tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
78881               }
78882             } else {
78883               tooltipBox = box;
78884             }
78885
78886             if (tooltipBox && html) {
78887               if (html.indexOf('**') !== -1) {
78888                 if (html.indexOf('<span') === 0) {
78889                   html = html.replace(/^(<span.*?>)(.+?)(\*\*)/, '$1<span>$2</span>$3');
78890                 } else {
78891                   html = html.replace(/^(.+?)(\*\*)/, '<span>$1</span>$2');
78892                 } // pseudo markdown bold text for the instruction section..
78893
78894
78895                 html = html.replace(/\*\*(.*?)\*\*/g, '<span class="instruction">$1</span>');
78896               }
78897
78898               html = html.replace(/\*(.*?)\*/g, '<em>$1</em>'); // emphasis
78899
78900               html = html.replace(/\{br\}/g, '<br/><br/>'); // linebreak
78901
78902               if (options.buttonText && options.buttonCallback) {
78903                 html += '<div class="button-section">' + '<button href="#" class="button action">' + options.buttonText + '</button></div>';
78904               }
78905
78906               var classes = 'curtain-tooltip popover tooltip arrowed in ' + (options.tooltipClass || '');
78907               tooltip.classed(classes, true).selectAll('.popover-inner').html(html);
78908
78909               if (options.buttonText && options.buttonCallback) {
78910                 var button = tooltip.selectAll('.button-section .button.action');
78911                 button.on('click', function (d3_event) {
78912                   d3_event.preventDefault();
78913                   options.buttonCallback();
78914                 });
78915               }
78916
78917               var tip = copyBox(tooltip.node().getBoundingClientRect()),
78918                   w = containerNode.clientWidth,
78919                   h = containerNode.clientHeight,
78920                   tooltipWidth = 200,
78921                   tooltipArrow = 5,
78922                   side,
78923                   pos; // hack: this will have bottom placement,
78924               // so need to reserve extra space for the tooltip illustration.
78925
78926               if (options.tooltipClass === 'intro-mouse') {
78927                 tip.height += 80;
78928               } // trim box dimensions to just the portion that fits in the container..
78929
78930
78931               if (tooltipBox.top + tooltipBox.height > h) {
78932                 tooltipBox.height -= tooltipBox.top + tooltipBox.height - h;
78933               }
78934
78935               if (tooltipBox.left + tooltipBox.width > w) {
78936                 tooltipBox.width -= tooltipBox.left + tooltipBox.width - w;
78937               } // determine tooltip placement..
78938
78939
78940               if (tooltipBox.top + tooltipBox.height < 100) {
78941                 // tooltip below box..
78942                 side = 'bottom';
78943                 pos = [tooltipBox.left + tooltipBox.width / 2 - tip.width / 2, tooltipBox.top + tooltipBox.height];
78944               } else if (tooltipBox.top > h - 140) {
78945                 // tooltip above box..
78946                 side = 'top';
78947                 pos = [tooltipBox.left + tooltipBox.width / 2 - tip.width / 2, tooltipBox.top - tip.height];
78948               } else {
78949                 // tooltip to the side of the tooltipBox..
78950                 var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
78951
78952                 if (_mainLocalizer.textDirection() === 'rtl') {
78953                   if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
78954                     side = 'right';
78955                     pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
78956                   } else {
78957                     side = 'left';
78958                     pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
78959                   }
78960                 } else {
78961                   if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w - 70) {
78962                     side = 'left';
78963                     pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
78964                   } else {
78965                     side = 'right';
78966                     pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
78967                   }
78968                 }
78969               }
78970
78971               if (options.duration !== 0 || !tooltip.classed(side)) {
78972                 tooltip.call(uiToggle(true));
78973               }
78974
78975               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
78976               // (doesn't affect the placement of the popover-arrow)
78977
78978               var shiftY = 0;
78979
78980               if (side === 'left' || side === 'right') {
78981                 if (pos[1] < 60) {
78982                   shiftY = 60 - pos[1];
78983                 } else if (pos[1] + tip.height > h - 100) {
78984                   shiftY = h - pos[1] - tip.height - 100;
78985                 }
78986               }
78987
78988               tooltip.selectAll('.popover-inner').style('top', shiftY + 'px');
78989             } else {
78990               tooltip.classed('in', false).call(uiToggle(false));
78991             }
78992
78993             curtain.cut(box, options.duration);
78994             return tooltip;
78995           };
78996
78997           curtain.cut = function (datum, duration) {
78998             darkness.datum(datum).interrupt();
78999             var selection;
79000
79001             if (duration === 0) {
79002               selection = darkness;
79003             } else {
79004               selection = darkness.transition().duration(duration || 600).ease(linear$1);
79005             }
79006
79007             selection.attr('d', function (d) {
79008               var containerWidth = containerNode.clientWidth;
79009               var containerHeight = containerNode.clientHeight;
79010               var string = 'M 0,0 L 0,' + containerHeight + ' L ' + containerWidth + ',' + containerHeight + 'L' + containerWidth + ',0 Z';
79011               if (!d) return string;
79012               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';
79013             });
79014           };
79015
79016           curtain.remove = function () {
79017             surface.remove();
79018             tooltip.remove();
79019             select(window).on('resize.curtain', null);
79020           }; // ClientRects are immutable, so copy them to an object,
79021           // in case we need to trim the height/width.
79022
79023
79024           function copyBox(src) {
79025             return {
79026               top: src.top,
79027               right: src.right,
79028               bottom: src.bottom,
79029               left: src.left,
79030               width: src.width,
79031               height: src.height
79032             };
79033           }
79034
79035           return curtain;
79036         }
79037
79038         function uiIntroWelcome(context, reveal) {
79039           var dispatch$1 = dispatch('done');
79040           var chapter = {
79041             title: 'intro.welcome.title'
79042           };
79043
79044           function welcome() {
79045             context.map().centerZoom([-85.63591, 41.94285], 19);
79046             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.welcome'), {
79047               buttonText: _t.html('intro.ok'),
79048               buttonCallback: practice
79049             });
79050           }
79051
79052           function practice() {
79053             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.practice'), {
79054               buttonText: _t.html('intro.ok'),
79055               buttonCallback: words
79056             });
79057           }
79058
79059           function words() {
79060             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.words'), {
79061               buttonText: _t.html('intro.ok'),
79062               buttonCallback: chapters
79063             });
79064           }
79065
79066           function chapters() {
79067             dispatch$1.call('done');
79068             reveal('.intro-nav-wrap .chapter-navigation', helpHtml('intro.welcome.chapters', {
79069               next: _t('intro.navigation.title')
79070             }));
79071           }
79072
79073           chapter.enter = function () {
79074             welcome();
79075           };
79076
79077           chapter.exit = function () {
79078             context.container().select('.curtain-tooltip.intro-mouse').selectAll('.counter').remove();
79079           };
79080
79081           chapter.restart = function () {
79082             chapter.exit();
79083             chapter.enter();
79084           };
79085
79086           return utilRebind(chapter, dispatch$1, 'on');
79087         }
79088
79089         function uiIntroNavigation(context, reveal) {
79090           var dispatch$1 = dispatch('done');
79091           var timeouts = [];
79092           var hallId = 'n2061';
79093           var townHall = [-85.63591, 41.94285];
79094           var springStreetId = 'w397';
79095           var springStreetEndId = 'n1834';
79096           var springStreet = [-85.63582, 41.94255];
79097           var onewayField = _mainPresetIndex.field('oneway');
79098           var maxspeedField = _mainPresetIndex.field('maxspeed');
79099           var chapter = {
79100             title: 'intro.navigation.title'
79101           };
79102
79103           function timeout(f, t) {
79104             timeouts.push(window.setTimeout(f, t));
79105           }
79106
79107           function eventCancel(d3_event) {
79108             d3_event.stopPropagation();
79109             d3_event.preventDefault();
79110           }
79111
79112           function isTownHallSelected() {
79113             var ids = context.selectedIDs();
79114             return ids.length === 1 && ids[0] === hallId;
79115           }
79116
79117           function dragMap() {
79118             context.enter(modeBrowse(context));
79119             context.history().reset('initial');
79120             var msec = transitionTime(townHall, context.map().center());
79121
79122             if (msec) {
79123               reveal(null, null, {
79124                 duration: 0
79125               });
79126             }
79127
79128             context.map().centerZoomEase(townHall, 19, msec);
79129             timeout(function () {
79130               var centerStart = context.map().center();
79131               var textId = context.lastPointerType() === 'mouse' ? 'drag' : 'drag_touch';
79132               var dragString = helpHtml('intro.navigation.map_info') + '{br}' + helpHtml('intro.navigation.' + textId);
79133               reveal('.surface', dragString);
79134               context.map().on('drawn.intro', function () {
79135                 reveal('.surface', dragString, {
79136                   duration: 0
79137                 });
79138               });
79139               context.map().on('move.intro', function () {
79140                 var centerNow = context.map().center();
79141
79142                 if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
79143                   context.map().on('move.intro', null);
79144                   timeout(function () {
79145                     continueTo(zoomMap);
79146                   }, 3000);
79147                 }
79148               });
79149             }, msec + 100);
79150
79151             function continueTo(nextStep) {
79152               context.map().on('move.intro drawn.intro', null);
79153               nextStep();
79154             }
79155           }
79156
79157           function zoomMap() {
79158             var zoomStart = context.map().zoom();
79159             var textId = context.lastPointerType() === 'mouse' ? 'zoom' : 'zoom_touch';
79160             var zoomString = helpHtml('intro.navigation.' + textId);
79161             reveal('.surface', zoomString);
79162             context.map().on('drawn.intro', function () {
79163               reveal('.surface', zoomString, {
79164                 duration: 0
79165               });
79166             });
79167             context.map().on('move.intro', function () {
79168               if (context.map().zoom() !== zoomStart) {
79169                 context.map().on('move.intro', null);
79170                 timeout(function () {
79171                   continueTo(features);
79172                 }, 3000);
79173               }
79174             });
79175
79176             function continueTo(nextStep) {
79177               context.map().on('move.intro drawn.intro', null);
79178               nextStep();
79179             }
79180           }
79181
79182           function features() {
79183             var onClick = function onClick() {
79184               continueTo(pointsLinesAreas);
79185             };
79186
79187             reveal('.surface', helpHtml('intro.navigation.features'), {
79188               buttonText: _t.html('intro.ok'),
79189               buttonCallback: onClick
79190             });
79191             context.map().on('drawn.intro', function () {
79192               reveal('.surface', helpHtml('intro.navigation.features'), {
79193                 duration: 0,
79194                 buttonText: _t.html('intro.ok'),
79195                 buttonCallback: onClick
79196               });
79197             });
79198
79199             function continueTo(nextStep) {
79200               context.map().on('drawn.intro', null);
79201               nextStep();
79202             }
79203           }
79204
79205           function pointsLinesAreas() {
79206             var onClick = function onClick() {
79207               continueTo(nodesWays);
79208             };
79209
79210             reveal('.surface', helpHtml('intro.navigation.points_lines_areas'), {
79211               buttonText: _t.html('intro.ok'),
79212               buttonCallback: onClick
79213             });
79214             context.map().on('drawn.intro', function () {
79215               reveal('.surface', helpHtml('intro.navigation.points_lines_areas'), {
79216                 duration: 0,
79217                 buttonText: _t.html('intro.ok'),
79218                 buttonCallback: onClick
79219               });
79220             });
79221
79222             function continueTo(nextStep) {
79223               context.map().on('drawn.intro', null);
79224               nextStep();
79225             }
79226           }
79227
79228           function nodesWays() {
79229             var onClick = function onClick() {
79230               continueTo(clickTownHall);
79231             };
79232
79233             reveal('.surface', helpHtml('intro.navigation.nodes_ways'), {
79234               buttonText: _t.html('intro.ok'),
79235               buttonCallback: onClick
79236             });
79237             context.map().on('drawn.intro', function () {
79238               reveal('.surface', helpHtml('intro.navigation.nodes_ways'), {
79239                 duration: 0,
79240                 buttonText: _t.html('intro.ok'),
79241                 buttonCallback: onClick
79242               });
79243             });
79244
79245             function continueTo(nextStep) {
79246               context.map().on('drawn.intro', null);
79247               nextStep();
79248             }
79249           }
79250
79251           function clickTownHall() {
79252             context.enter(modeBrowse(context));
79253             context.history().reset('initial');
79254             var entity = context.hasEntity(hallId);
79255             if (!entity) return;
79256             reveal(null, null, {
79257               duration: 0
79258             });
79259             context.map().centerZoomEase(entity.loc, 19, 500);
79260             timeout(function () {
79261               var entity = context.hasEntity(hallId);
79262               if (!entity) return;
79263               var box = pointBox(entity.loc, context);
79264               var textId = context.lastPointerType() === 'mouse' ? 'click_townhall' : 'tap_townhall';
79265               reveal(box, helpHtml('intro.navigation.' + textId));
79266               context.map().on('move.intro drawn.intro', function () {
79267                 var entity = context.hasEntity(hallId);
79268                 if (!entity) return;
79269                 var box = pointBox(entity.loc, context);
79270                 reveal(box, helpHtml('intro.navigation.' + textId), {
79271                   duration: 0
79272                 });
79273               });
79274               context.on('enter.intro', function () {
79275                 if (isTownHallSelected()) continueTo(selectedTownHall);
79276               });
79277             }, 550); // after centerZoomEase
79278
79279             context.history().on('change.intro', function () {
79280               if (!context.hasEntity(hallId)) {
79281                 continueTo(clickTownHall);
79282               }
79283             });
79284
79285             function continueTo(nextStep) {
79286               context.on('enter.intro', null);
79287               context.map().on('move.intro drawn.intro', null);
79288               context.history().on('change.intro', null);
79289               nextStep();
79290             }
79291           }
79292
79293           function selectedTownHall() {
79294             if (!isTownHallSelected()) return clickTownHall();
79295             var entity = context.hasEntity(hallId);
79296             if (!entity) return clickTownHall();
79297             var box = pointBox(entity.loc, context);
79298
79299             var onClick = function onClick() {
79300               continueTo(editorTownHall);
79301             };
79302
79303             reveal(box, helpHtml('intro.navigation.selected_townhall'), {
79304               buttonText: _t.html('intro.ok'),
79305               buttonCallback: onClick
79306             });
79307             context.map().on('move.intro drawn.intro', function () {
79308               var entity = context.hasEntity(hallId);
79309               if (!entity) return;
79310               var box = pointBox(entity.loc, context);
79311               reveal(box, helpHtml('intro.navigation.selected_townhall'), {
79312                 duration: 0,
79313                 buttonText: _t.html('intro.ok'),
79314                 buttonCallback: onClick
79315               });
79316             });
79317             context.history().on('change.intro', function () {
79318               if (!context.hasEntity(hallId)) {
79319                 continueTo(clickTownHall);
79320               }
79321             });
79322
79323             function continueTo(nextStep) {
79324               context.map().on('move.intro drawn.intro', null);
79325               context.history().on('change.intro', null);
79326               nextStep();
79327             }
79328           }
79329
79330           function editorTownHall() {
79331             if (!isTownHallSelected()) return clickTownHall(); // disallow scrolling
79332
79333             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79334
79335             var onClick = function onClick() {
79336               continueTo(presetTownHall);
79337             };
79338
79339             reveal('.entity-editor-pane', helpHtml('intro.navigation.editor_townhall'), {
79340               buttonText: _t.html('intro.ok'),
79341               buttonCallback: onClick
79342             });
79343             context.on('exit.intro', function () {
79344               continueTo(clickTownHall);
79345             });
79346             context.history().on('change.intro', function () {
79347               if (!context.hasEntity(hallId)) {
79348                 continueTo(clickTownHall);
79349               }
79350             });
79351
79352             function continueTo(nextStep) {
79353               context.on('exit.intro', null);
79354               context.history().on('change.intro', null);
79355               context.container().select('.inspector-wrap').on('wheel.intro', null);
79356               nextStep();
79357             }
79358           }
79359
79360           function presetTownHall() {
79361             if (!isTownHallSelected()) return clickTownHall(); // reset pane, in case user happened to change it..
79362
79363             context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // disallow scrolling
79364
79365             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel); // preset match, in case the user happened to change it.
79366
79367             var entity = context.entity(context.selectedIDs()[0]);
79368             var preset = _mainPresetIndex.match(entity, context.graph());
79369
79370             var onClick = function onClick() {
79371               continueTo(fieldsTownHall);
79372             };
79373
79374             reveal('.entity-editor-pane .section-feature-type', helpHtml('intro.navigation.preset_townhall', {
79375               preset: preset.name()
79376             }), {
79377               buttonText: _t.html('intro.ok'),
79378               buttonCallback: onClick
79379             });
79380             context.on('exit.intro', function () {
79381               continueTo(clickTownHall);
79382             });
79383             context.history().on('change.intro', function () {
79384               if (!context.hasEntity(hallId)) {
79385                 continueTo(clickTownHall);
79386               }
79387             });
79388
79389             function continueTo(nextStep) {
79390               context.on('exit.intro', null);
79391               context.history().on('change.intro', null);
79392               context.container().select('.inspector-wrap').on('wheel.intro', null);
79393               nextStep();
79394             }
79395           }
79396
79397           function fieldsTownHall() {
79398             if (!isTownHallSelected()) return clickTownHall(); // reset pane, in case user happened to change it..
79399
79400             context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // disallow scrolling
79401
79402             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79403
79404             var onClick = function onClick() {
79405               continueTo(closeTownHall);
79406             };
79407
79408             reveal('.entity-editor-pane .section-preset-fields', helpHtml('intro.navigation.fields_townhall'), {
79409               buttonText: _t.html('intro.ok'),
79410               buttonCallback: onClick
79411             });
79412             context.on('exit.intro', function () {
79413               continueTo(clickTownHall);
79414             });
79415             context.history().on('change.intro', function () {
79416               if (!context.hasEntity(hallId)) {
79417                 continueTo(clickTownHall);
79418               }
79419             });
79420
79421             function continueTo(nextStep) {
79422               context.on('exit.intro', null);
79423               context.history().on('change.intro', null);
79424               context.container().select('.inspector-wrap').on('wheel.intro', null);
79425               nextStep();
79426             }
79427           }
79428
79429           function closeTownHall() {
79430             if (!isTownHallSelected()) return clickTownHall();
79431             var selector = '.entity-editor-pane button.close svg use';
79432             var href = select(selector).attr('href') || '#iD-icon-close';
79433             reveal('.entity-editor-pane', helpHtml('intro.navigation.close_townhall', {
79434               button: icon(href, 'inline')
79435             }));
79436             context.on('exit.intro', function () {
79437               continueTo(searchStreet);
79438             });
79439             context.history().on('change.intro', function () {
79440               // update the close icon in the tooltip if the user edits something.
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.close_townhall', {
79444                 button: icon(href, 'inline')
79445               }), {
79446                 duration: 0
79447               });
79448             });
79449
79450             function continueTo(nextStep) {
79451               context.on('exit.intro', null);
79452               context.history().on('change.intro', null);
79453               nextStep();
79454             }
79455           }
79456
79457           function searchStreet() {
79458             context.enter(modeBrowse(context));
79459             context.history().reset('initial'); // ensure spring street exists
79460
79461             var msec = transitionTime(springStreet, context.map().center());
79462
79463             if (msec) {
79464               reveal(null, null, {
79465                 duration: 0
79466               });
79467             }
79468
79469             context.map().centerZoomEase(springStreet, 19, msec); // ..and user can see it
79470
79471             timeout(function () {
79472               reveal('.search-header input', helpHtml('intro.navigation.search_street', {
79473                 name: _t('intro.graph.name.spring-street')
79474               }));
79475               context.container().select('.search-header input').on('keyup.intro', checkSearchResult);
79476             }, msec + 100);
79477           }
79478
79479           function checkSearchResult() {
79480             var first = context.container().select('.feature-list-item:nth-child(0n+2)'); // skip "No Results" item
79481
79482             var firstName = first.select('.entity-name');
79483             var name = _t('intro.graph.name.spring-street');
79484
79485             if (!firstName.empty() && firstName.html() === name) {
79486               reveal(first.node(), helpHtml('intro.navigation.choose_street', {
79487                 name: name
79488               }), {
79489                 duration: 300
79490               });
79491               context.on('exit.intro', function () {
79492                 continueTo(selectedStreet);
79493               });
79494               context.container().select('.search-header input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
79495             }
79496
79497             function continueTo(nextStep) {
79498               context.on('exit.intro', null);
79499               context.container().select('.search-header input').on('keydown.intro', null).on('keyup.intro', null);
79500               nextStep();
79501             }
79502           }
79503
79504           function selectedStreet() {
79505             if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
79506               return searchStreet();
79507             }
79508
79509             var onClick = function onClick() {
79510               continueTo(editorStreet);
79511             };
79512
79513             var entity = context.entity(springStreetEndId);
79514             var box = pointBox(entity.loc, context);
79515             box.height = 500;
79516             reveal(box, helpHtml('intro.navigation.selected_street', {
79517               name: _t('intro.graph.name.spring-street')
79518             }), {
79519               duration: 600,
79520               buttonText: _t.html('intro.ok'),
79521               buttonCallback: onClick
79522             });
79523             timeout(function () {
79524               context.map().on('move.intro drawn.intro', function () {
79525                 var entity = context.hasEntity(springStreetEndId);
79526                 if (!entity) return;
79527                 var box = pointBox(entity.loc, context);
79528                 box.height = 500;
79529                 reveal(box, helpHtml('intro.navigation.selected_street', {
79530                   name: _t('intro.graph.name.spring-street')
79531                 }), {
79532                   duration: 0,
79533                   buttonText: _t.html('intro.ok'),
79534                   buttonCallback: onClick
79535                 });
79536               });
79537             }, 600); // after reveal.
79538
79539             context.on('enter.intro', function (mode) {
79540               if (!context.hasEntity(springStreetId)) {
79541                 return continueTo(searchStreet);
79542               }
79543
79544               var ids = context.selectedIDs();
79545
79546               if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) {
79547                 // keep Spring Street selected..
79548                 context.enter(modeSelect(context, [springStreetId]));
79549               }
79550             });
79551             context.history().on('change.intro', function () {
79552               if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
79553                 timeout(function () {
79554                   continueTo(searchStreet);
79555                 }, 300); // after any transition (e.g. if user deleted intersection)
79556               }
79557             });
79558
79559             function continueTo(nextStep) {
79560               context.map().on('move.intro drawn.intro', null);
79561               context.on('enter.intro', null);
79562               context.history().on('change.intro', null);
79563               nextStep();
79564             }
79565           }
79566
79567           function editorStreet() {
79568             var selector = '.entity-editor-pane button.close svg use';
79569             var href = select(selector).attr('href') || '#iD-icon-close';
79570             reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', {
79571               button: icon(href, 'inline'),
79572               field1: onewayField.label(),
79573               field2: maxspeedField.label()
79574             }));
79575             context.on('exit.intro', function () {
79576               continueTo(play);
79577             });
79578             context.history().on('change.intro', function () {
79579               // update the close icon in the tooltip if the user edits something.
79580               var selector = '.entity-editor-pane button.close svg use';
79581               var href = select(selector).attr('href') || '#iD-icon-close';
79582               reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', {
79583                 button: icon(href, 'inline'),
79584                 field1: onewayField.label(),
79585                 field2: maxspeedField.label()
79586               }), {
79587                 duration: 0
79588               });
79589             });
79590
79591             function continueTo(nextStep) {
79592               context.on('exit.intro', null);
79593               context.history().on('change.intro', null);
79594               nextStep();
79595             }
79596           }
79597
79598           function play() {
79599             dispatch$1.call('done');
79600             reveal('.ideditor', helpHtml('intro.navigation.play', {
79601               next: _t('intro.points.title')
79602             }), {
79603               tooltipBox: '.intro-nav-wrap .chapter-point',
79604               buttonText: _t.html('intro.ok'),
79605               buttonCallback: function buttonCallback() {
79606                 reveal('.ideditor');
79607               }
79608             });
79609           }
79610
79611           chapter.enter = function () {
79612             dragMap();
79613           };
79614
79615           chapter.exit = function () {
79616             timeouts.forEach(window.clearTimeout);
79617             context.on('enter.intro exit.intro', null);
79618             context.map().on('move.intro drawn.intro', null);
79619             context.history().on('change.intro', null);
79620             context.container().select('.inspector-wrap').on('wheel.intro', null);
79621             context.container().select('.search-header input').on('keydown.intro keyup.intro', null);
79622           };
79623
79624           chapter.restart = function () {
79625             chapter.exit();
79626             chapter.enter();
79627           };
79628
79629           return utilRebind(chapter, dispatch$1, 'on');
79630         }
79631
79632         function uiIntroPoint(context, reveal) {
79633           var dispatch$1 = dispatch('done');
79634           var timeouts = [];
79635           var intersection = [-85.63279, 41.94394];
79636           var building = [-85.632422, 41.944045];
79637           var cafePreset = _mainPresetIndex.item('amenity/cafe');
79638           var _pointID = null;
79639           var chapter = {
79640             title: 'intro.points.title'
79641           };
79642
79643           function timeout(f, t) {
79644             timeouts.push(window.setTimeout(f, t));
79645           }
79646
79647           function eventCancel(d3_event) {
79648             d3_event.stopPropagation();
79649             d3_event.preventDefault();
79650           }
79651
79652           function addPoint() {
79653             context.enter(modeBrowse(context));
79654             context.history().reset('initial');
79655             var msec = transitionTime(intersection, context.map().center());
79656
79657             if (msec) {
79658               reveal(null, null, {
79659                 duration: 0
79660               });
79661             }
79662
79663             context.map().centerZoomEase(intersection, 19, msec);
79664             timeout(function () {
79665               var tooltip = reveal('button.add-point', helpHtml('intro.points.points_info') + '{br}' + helpHtml('intro.points.add_point'));
79666               _pointID = null;
79667               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-points');
79668               context.on('enter.intro', function (mode) {
79669                 if (mode.id !== 'add-point') return;
79670                 continueTo(placePoint);
79671               });
79672             }, msec + 100);
79673
79674             function continueTo(nextStep) {
79675               context.on('enter.intro', null);
79676               nextStep();
79677             }
79678           }
79679
79680           function placePoint() {
79681             if (context.mode().id !== 'add-point') {
79682               return chapter.restart();
79683             }
79684
79685             var pointBox = pad(building, 150, context);
79686             var textId = context.lastPointerType() === 'mouse' ? 'place_point' : 'place_point_touch';
79687             reveal(pointBox, helpHtml('intro.points.' + textId));
79688             context.map().on('move.intro drawn.intro', function () {
79689               pointBox = pad(building, 150, context);
79690               reveal(pointBox, helpHtml('intro.points.' + textId), {
79691                 duration: 0
79692               });
79693             });
79694             context.on('enter.intro', function (mode) {
79695               if (mode.id !== 'select') return chapter.restart();
79696               _pointID = context.mode().selectedIDs()[0];
79697               continueTo(searchPreset);
79698             });
79699
79700             function continueTo(nextStep) {
79701               context.map().on('move.intro drawn.intro', null);
79702               context.on('enter.intro', null);
79703               nextStep();
79704             }
79705           }
79706
79707           function searchPreset() {
79708             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79709               return addPoint();
79710             } // disallow scrolling
79711
79712
79713             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79714             context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
79715             reveal('.preset-search-input', helpHtml('intro.points.search_cafe', {
79716               preset: cafePreset.name()
79717             }));
79718             context.on('enter.intro', function (mode) {
79719               if (!_pointID || !context.hasEntity(_pointID)) {
79720                 return continueTo(addPoint);
79721               }
79722
79723               var ids = context.selectedIDs();
79724
79725               if (mode.id !== 'select' || !ids.length || ids[0] !== _pointID) {
79726                 // keep the user's point selected..
79727                 context.enter(modeSelect(context, [_pointID])); // disallow scrolling
79728
79729                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79730                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
79731                 reveal('.preset-search-input', helpHtml('intro.points.search_cafe', {
79732                   preset: cafePreset.name()
79733                 }));
79734                 context.history().on('change.intro', null);
79735               }
79736             });
79737
79738             function checkPresetSearch() {
79739               var first = context.container().select('.preset-list-item:first-child');
79740
79741               if (first.classed('preset-amenity-cafe')) {
79742                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
79743                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.points.choose_cafe', {
79744                   preset: cafePreset.name()
79745                 }), {
79746                   duration: 300
79747                 });
79748                 context.history().on('change.intro', function () {
79749                   continueTo(aboutFeatureEditor);
79750                 });
79751               }
79752             }
79753
79754             function continueTo(nextStep) {
79755               context.on('enter.intro', null);
79756               context.history().on('change.intro', null);
79757               context.container().select('.inspector-wrap').on('wheel.intro', null);
79758               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
79759               nextStep();
79760             }
79761           }
79762
79763           function aboutFeatureEditor() {
79764             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79765               return addPoint();
79766             }
79767
79768             timeout(function () {
79769               reveal('.entity-editor-pane', helpHtml('intro.points.feature_editor'), {
79770                 tooltipClass: 'intro-points-describe',
79771                 buttonText: _t.html('intro.ok'),
79772                 buttonCallback: function buttonCallback() {
79773                   continueTo(addName);
79774                 }
79775               });
79776             }, 400);
79777             context.on('exit.intro', function () {
79778               // if user leaves select mode here, just continue with the tutorial.
79779               continueTo(reselectPoint);
79780             });
79781
79782             function continueTo(nextStep) {
79783               context.on('exit.intro', null);
79784               nextStep();
79785             }
79786           }
79787
79788           function addName() {
79789             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79790               return addPoint();
79791             } // reset pane, in case user happened to change it..
79792
79793
79794             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
79795             var addNameString = helpHtml('intro.points.fields_info') + '{br}' + helpHtml('intro.points.add_name');
79796             timeout(function () {
79797               // It's possible for the user to add a name in a previous step..
79798               // If so, don't tell them to add the name in this step.
79799               // Give them an OK button instead.
79800               var entity = context.entity(_pointID);
79801
79802               if (entity.tags.name) {
79803                 var tooltip = reveal('.entity-editor-pane', addNameString, {
79804                   tooltipClass: 'intro-points-describe',
79805                   buttonText: _t.html('intro.ok'),
79806                   buttonCallback: function buttonCallback() {
79807                     continueTo(addCloseEditor);
79808                   }
79809                 });
79810                 tooltip.select('.instruction').style('display', 'none');
79811               } else {
79812                 reveal('.entity-editor-pane', addNameString, {
79813                   tooltipClass: 'intro-points-describe'
79814                 });
79815               }
79816             }, 400);
79817             context.history().on('change.intro', function () {
79818               continueTo(addCloseEditor);
79819             });
79820             context.on('exit.intro', function () {
79821               // if user leaves select mode here, just continue with the tutorial.
79822               continueTo(reselectPoint);
79823             });
79824
79825             function continueTo(nextStep) {
79826               context.on('exit.intro', null);
79827               context.history().on('change.intro', null);
79828               nextStep();
79829             }
79830           }
79831
79832           function addCloseEditor() {
79833             // reset pane, in case user happened to change it..
79834             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
79835             var selector = '.entity-editor-pane button.close svg use';
79836             var href = select(selector).attr('href') || '#iD-icon-close';
79837             context.on('exit.intro', function () {
79838               continueTo(reselectPoint);
79839             });
79840             reveal('.entity-editor-pane', helpHtml('intro.points.add_close', {
79841               button: icon(href, 'inline')
79842             }));
79843
79844             function continueTo(nextStep) {
79845               context.on('exit.intro', null);
79846               nextStep();
79847             }
79848           }
79849
79850           function reselectPoint() {
79851             if (!_pointID) return chapter.restart();
79852             var entity = context.hasEntity(_pointID);
79853             if (!entity) return chapter.restart(); // make sure it's still a cafe, in case user somehow changed it..
79854
79855             var oldPreset = _mainPresetIndex.match(entity, context.graph());
79856             context.replace(actionChangePreset(_pointID, oldPreset, cafePreset));
79857             context.enter(modeBrowse(context));
79858             var msec = transitionTime(entity.loc, context.map().center());
79859
79860             if (msec) {
79861               reveal(null, null, {
79862                 duration: 0
79863               });
79864             }
79865
79866             context.map().centerEase(entity.loc, msec);
79867             timeout(function () {
79868               var box = pointBox(entity.loc, context);
79869               reveal(box, helpHtml('intro.points.reselect'), {
79870                 duration: 600
79871               });
79872               timeout(function () {
79873                 context.map().on('move.intro drawn.intro', function () {
79874                   var entity = context.hasEntity(_pointID);
79875                   if (!entity) return chapter.restart();
79876                   var box = pointBox(entity.loc, context);
79877                   reveal(box, helpHtml('intro.points.reselect'), {
79878                     duration: 0
79879                   });
79880                 });
79881               }, 600); // after reveal..
79882
79883               context.on('enter.intro', function (mode) {
79884                 if (mode.id !== 'select') return;
79885                 continueTo(updatePoint);
79886               });
79887             }, msec + 100);
79888
79889             function continueTo(nextStep) {
79890               context.map().on('move.intro drawn.intro', null);
79891               context.on('enter.intro', null);
79892               nextStep();
79893             }
79894           }
79895
79896           function updatePoint() {
79897             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79898               return continueTo(reselectPoint);
79899             } // reset pane, in case user happened to untag the point..
79900
79901
79902             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
79903             context.on('exit.intro', function () {
79904               continueTo(reselectPoint);
79905             });
79906             context.history().on('change.intro', function () {
79907               continueTo(updateCloseEditor);
79908             });
79909             timeout(function () {
79910               reveal('.entity-editor-pane', helpHtml('intro.points.update'), {
79911                 tooltipClass: 'intro-points-describe'
79912               });
79913             }, 400);
79914
79915             function continueTo(nextStep) {
79916               context.on('exit.intro', null);
79917               context.history().on('change.intro', null);
79918               nextStep();
79919             }
79920           }
79921
79922           function updateCloseEditor() {
79923             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79924               return continueTo(reselectPoint);
79925             } // reset pane, in case user happened to change it..
79926
79927
79928             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
79929             context.on('exit.intro', function () {
79930               continueTo(rightClickPoint);
79931             });
79932             timeout(function () {
79933               reveal('.entity-editor-pane', helpHtml('intro.points.update_close', {
79934                 button: icon('#iD-icon-close', 'inline')
79935               }));
79936             }, 500);
79937
79938             function continueTo(nextStep) {
79939               context.on('exit.intro', null);
79940               nextStep();
79941             }
79942           }
79943
79944           function rightClickPoint() {
79945             if (!_pointID) return chapter.restart();
79946             var entity = context.hasEntity(_pointID);
79947             if (!entity) return chapter.restart();
79948             context.enter(modeBrowse(context));
79949             var box = pointBox(entity.loc, context);
79950             var textId = context.lastPointerType() === 'mouse' ? 'rightclick' : 'edit_menu_touch';
79951             reveal(box, helpHtml('intro.points.' + textId), {
79952               duration: 600
79953             });
79954             timeout(function () {
79955               context.map().on('move.intro', function () {
79956                 var entity = context.hasEntity(_pointID);
79957                 if (!entity) return chapter.restart();
79958                 var box = pointBox(entity.loc, context);
79959                 reveal(box, helpHtml('intro.points.' + textId), {
79960                   duration: 0
79961                 });
79962               });
79963             }, 600); // after reveal
79964
79965             context.on('enter.intro', function (mode) {
79966               if (mode.id !== 'select') return;
79967               var ids = context.selectedIDs();
79968               if (ids.length !== 1 || ids[0] !== _pointID) return;
79969               timeout(function () {
79970                 var node = selectMenuItem(context, 'delete').node();
79971                 if (!node) return;
79972                 continueTo(enterDelete);
79973               }, 50); // after menu visible
79974             });
79975
79976             function continueTo(nextStep) {
79977               context.on('enter.intro', null);
79978               context.map().on('move.intro', null);
79979               nextStep();
79980             }
79981           }
79982
79983           function enterDelete() {
79984             if (!_pointID) return chapter.restart();
79985             var entity = context.hasEntity(_pointID);
79986             if (!entity) return chapter.restart();
79987             var node = selectMenuItem(context, 'delete').node();
79988
79989             if (!node) {
79990               return continueTo(rightClickPoint);
79991             }
79992
79993             reveal('.edit-menu', helpHtml('intro.points.delete'), {
79994               padding: 50
79995             });
79996             timeout(function () {
79997               context.map().on('move.intro', function () {
79998                 reveal('.edit-menu', helpHtml('intro.points.delete'), {
79999                   duration: 0,
80000                   padding: 50
80001                 });
80002               });
80003             }, 300); // after menu visible
80004
80005             context.on('exit.intro', function () {
80006               if (!_pointID) return chapter.restart();
80007               var entity = context.hasEntity(_pointID);
80008               if (entity) return continueTo(rightClickPoint); // point still exists
80009             });
80010             context.history().on('change.intro', function (changed) {
80011               if (changed.deleted().length) {
80012                 continueTo(undo);
80013               }
80014             });
80015
80016             function continueTo(nextStep) {
80017               context.map().on('move.intro', null);
80018               context.history().on('change.intro', null);
80019               context.on('exit.intro', null);
80020               nextStep();
80021             }
80022           }
80023
80024           function undo() {
80025             context.history().on('change.intro', function () {
80026               continueTo(play);
80027             });
80028             reveal('.top-toolbar button.undo-button', helpHtml('intro.points.undo'));
80029
80030             function continueTo(nextStep) {
80031               context.history().on('change.intro', null);
80032               nextStep();
80033             }
80034           }
80035
80036           function play() {
80037             dispatch$1.call('done');
80038             reveal('.ideditor', helpHtml('intro.points.play', {
80039               next: _t('intro.areas.title')
80040             }), {
80041               tooltipBox: '.intro-nav-wrap .chapter-area',
80042               buttonText: _t.html('intro.ok'),
80043               buttonCallback: function buttonCallback() {
80044                 reveal('.ideditor');
80045               }
80046             });
80047           }
80048
80049           chapter.enter = function () {
80050             addPoint();
80051           };
80052
80053           chapter.exit = function () {
80054             timeouts.forEach(window.clearTimeout);
80055             context.on('enter.intro exit.intro', null);
80056             context.map().on('move.intro drawn.intro', null);
80057             context.history().on('change.intro', null);
80058             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80059             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
80060           };
80061
80062           chapter.restart = function () {
80063             chapter.exit();
80064             chapter.enter();
80065           };
80066
80067           return utilRebind(chapter, dispatch$1, 'on');
80068         }
80069
80070         function uiIntroArea(context, reveal) {
80071           var dispatch$1 = dispatch('done');
80072           var playground = [-85.63552, 41.94159];
80073           var playgroundPreset = _mainPresetIndex.item('leisure/playground');
80074           var nameField = _mainPresetIndex.field('name');
80075           var descriptionField = _mainPresetIndex.field('description');
80076           var timeouts = [];
80077
80078           var _areaID;
80079
80080           var chapter = {
80081             title: 'intro.areas.title'
80082           };
80083
80084           function timeout(f, t) {
80085             timeouts.push(window.setTimeout(f, t));
80086           }
80087
80088           function eventCancel(d3_event) {
80089             d3_event.stopPropagation();
80090             d3_event.preventDefault();
80091           }
80092
80093           function revealPlayground(center, text, options) {
80094             var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
80095             var box = pad(center, padding, context);
80096             reveal(box, text, options);
80097           }
80098
80099           function addArea() {
80100             context.enter(modeBrowse(context));
80101             context.history().reset('initial');
80102             _areaID = null;
80103             var msec = transitionTime(playground, context.map().center());
80104
80105             if (msec) {
80106               reveal(null, null, {
80107                 duration: 0
80108               });
80109             }
80110
80111             context.map().centerZoomEase(playground, 19, msec);
80112             timeout(function () {
80113               var tooltip = reveal('button.add-area', helpHtml('intro.areas.add_playground'));
80114               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-areas');
80115               context.on('enter.intro', function (mode) {
80116                 if (mode.id !== 'add-area') return;
80117                 continueTo(startPlayground);
80118               });
80119             }, msec + 100);
80120
80121             function continueTo(nextStep) {
80122               context.on('enter.intro', null);
80123               nextStep();
80124             }
80125           }
80126
80127           function startPlayground() {
80128             if (context.mode().id !== 'add-area') {
80129               return chapter.restart();
80130             }
80131
80132             _areaID = null;
80133             context.map().zoomEase(19.5, 500);
80134             timeout(function () {
80135               var textId = context.lastPointerType() === 'mouse' ? 'starting_node_click' : 'starting_node_tap';
80136               var startDrawString = helpHtml('intro.areas.start_playground') + helpHtml('intro.areas.' + textId);
80137               revealPlayground(playground, startDrawString, {
80138                 duration: 250
80139               });
80140               timeout(function () {
80141                 context.map().on('move.intro drawn.intro', function () {
80142                   revealPlayground(playground, startDrawString, {
80143                     duration: 0
80144                   });
80145                 });
80146                 context.on('enter.intro', function (mode) {
80147                   if (mode.id !== 'draw-area') return chapter.restart();
80148                   continueTo(continuePlayground);
80149                 });
80150               }, 250); // after reveal
80151             }, 550); // after easing
80152
80153             function continueTo(nextStep) {
80154               context.map().on('move.intro drawn.intro', null);
80155               context.on('enter.intro', null);
80156               nextStep();
80157             }
80158           }
80159
80160           function continuePlayground() {
80161             if (context.mode().id !== 'draw-area') {
80162               return chapter.restart();
80163             }
80164
80165             _areaID = null;
80166             revealPlayground(playground, helpHtml('intro.areas.continue_playground'), {
80167               duration: 250
80168             });
80169             timeout(function () {
80170               context.map().on('move.intro drawn.intro', function () {
80171                 revealPlayground(playground, helpHtml('intro.areas.continue_playground'), {
80172                   duration: 0
80173                 });
80174               });
80175             }, 250); // after reveal
80176
80177             context.on('enter.intro', function (mode) {
80178               if (mode.id === 'draw-area') {
80179                 var entity = context.hasEntity(context.selectedIDs()[0]);
80180
80181                 if (entity && entity.nodes.length >= 6) {
80182                   return continueTo(finishPlayground);
80183                 } else {
80184                   return;
80185                 }
80186               } else if (mode.id === 'select') {
80187                 _areaID = context.selectedIDs()[0];
80188                 return continueTo(searchPresets);
80189               } else {
80190                 return chapter.restart();
80191               }
80192             });
80193
80194             function continueTo(nextStep) {
80195               context.map().on('move.intro drawn.intro', null);
80196               context.on('enter.intro', null);
80197               nextStep();
80198             }
80199           }
80200
80201           function finishPlayground() {
80202             if (context.mode().id !== 'draw-area') {
80203               return chapter.restart();
80204             }
80205
80206             _areaID = null;
80207             var finishString = helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.areas.finish_playground');
80208             revealPlayground(playground, finishString, {
80209               duration: 250
80210             });
80211             timeout(function () {
80212               context.map().on('move.intro drawn.intro', function () {
80213                 revealPlayground(playground, finishString, {
80214                   duration: 0
80215                 });
80216               });
80217             }, 250); // after reveal
80218
80219             context.on('enter.intro', function (mode) {
80220               if (mode.id === 'draw-area') {
80221                 return;
80222               } else if (mode.id === 'select') {
80223                 _areaID = context.selectedIDs()[0];
80224                 return continueTo(searchPresets);
80225               } else {
80226                 return chapter.restart();
80227               }
80228             });
80229
80230             function continueTo(nextStep) {
80231               context.map().on('move.intro drawn.intro', null);
80232               context.on('enter.intro', null);
80233               nextStep();
80234             }
80235           }
80236
80237           function searchPresets() {
80238             if (!_areaID || !context.hasEntity(_areaID)) {
80239               return addArea();
80240             }
80241
80242             var ids = context.selectedIDs();
80243
80244             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
80245               context.enter(modeSelect(context, [_areaID]));
80246             } // disallow scrolling
80247
80248
80249             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80250             timeout(function () {
80251               // reset pane, in case user somehow happened to change it..
80252               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
80253               context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
80254               reveal('.preset-search-input', helpHtml('intro.areas.search_playground', {
80255                 preset: playgroundPreset.name()
80256               }));
80257             }, 400); // after preset list pane visible..
80258
80259             context.on('enter.intro', function (mode) {
80260               if (!_areaID || !context.hasEntity(_areaID)) {
80261                 return continueTo(addArea);
80262               }
80263
80264               var ids = context.selectedIDs();
80265
80266               if (mode.id !== 'select' || !ids.length || ids[0] !== _areaID) {
80267                 // keep the user's area selected..
80268                 context.enter(modeSelect(context, [_areaID])); // reset pane, in case user somehow happened to change it..
80269
80270                 context.container().select('.inspector-wrap .panewrap').style('right', '-100%'); // disallow scrolling
80271
80272                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80273                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
80274                 reveal('.preset-search-input', helpHtml('intro.areas.search_playground', {
80275                   preset: playgroundPreset.name()
80276                 }));
80277                 context.history().on('change.intro', null);
80278               }
80279             });
80280
80281             function checkPresetSearch() {
80282               var first = context.container().select('.preset-list-item:first-child');
80283
80284               if (first.classed('preset-leisure-playground')) {
80285                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.areas.choose_playground', {
80286                   preset: playgroundPreset.name()
80287                 }), {
80288                   duration: 300
80289                 });
80290                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
80291                 context.history().on('change.intro', function () {
80292                   continueTo(clickAddField);
80293                 });
80294               }
80295             }
80296
80297             function continueTo(nextStep) {
80298               context.container().select('.inspector-wrap').on('wheel.intro', null);
80299               context.on('enter.intro', null);
80300               context.history().on('change.intro', null);
80301               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
80302               nextStep();
80303             }
80304           }
80305
80306           function clickAddField() {
80307             if (!_areaID || !context.hasEntity(_areaID)) {
80308               return addArea();
80309             }
80310
80311             var ids = context.selectedIDs();
80312
80313             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
80314               return searchPresets();
80315             }
80316
80317             if (!context.container().select('.form-field-description').empty()) {
80318               return continueTo(describePlayground);
80319             } // disallow scrolling
80320
80321
80322             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80323             timeout(function () {
80324               // reset pane, in case user somehow happened to change it..
80325               context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // It's possible for the user to add a description in a previous step..
80326               // If they did this already, just continue to next step.
80327
80328               var entity = context.entity(_areaID);
80329
80330               if (entity.tags.description) {
80331                 return continueTo(play);
80332               } // scroll "Add field" into view
80333
80334
80335               var box = context.container().select('.more-fields').node().getBoundingClientRect();
80336
80337               if (box.top > 300) {
80338                 var pane = context.container().select('.entity-editor-pane .inspector-body');
80339                 var start = pane.node().scrollTop;
80340                 var end = start + (box.top - 300);
80341                 pane.transition().duration(250).tween('scroll.inspector', function () {
80342                   var node = this;
80343                   var i = d3_interpolateNumber(start, end);
80344                   return function (t) {
80345                     node.scrollTop = i(t);
80346                   };
80347                 });
80348               }
80349
80350               timeout(function () {
80351                 reveal('.more-fields .combobox-input', helpHtml('intro.areas.add_field', {
80352                   name: nameField.label(),
80353                   description: descriptionField.label()
80354                 }), {
80355                   duration: 300
80356                 });
80357                 context.container().select('.more-fields .combobox-input').on('click.intro', function () {
80358                   // Watch for the combobox to appear...
80359                   var watcher;
80360                   watcher = window.setInterval(function () {
80361                     if (!context.container().select('div.combobox').empty()) {
80362                       window.clearInterval(watcher);
80363                       continueTo(chooseDescriptionField);
80364                     }
80365                   }, 300);
80366                 });
80367               }, 300); // after "Add Field" visible
80368             }, 400); // after editor pane visible
80369
80370             context.on('exit.intro', function () {
80371               return continueTo(searchPresets);
80372             });
80373
80374             function continueTo(nextStep) {
80375               context.container().select('.inspector-wrap').on('wheel.intro', null);
80376               context.container().select('.more-fields .combobox-input').on('click.intro', null);
80377               context.on('exit.intro', null);
80378               nextStep();
80379             }
80380           }
80381
80382           function chooseDescriptionField() {
80383             if (!_areaID || !context.hasEntity(_areaID)) {
80384               return addArea();
80385             }
80386
80387             var ids = context.selectedIDs();
80388
80389             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
80390               return searchPresets();
80391             }
80392
80393             if (!context.container().select('.form-field-description').empty()) {
80394               return continueTo(describePlayground);
80395             } // Make sure combobox is ready..
80396
80397
80398             if (context.container().select('div.combobox').empty()) {
80399               return continueTo(clickAddField);
80400             } // Watch for the combobox to go away..
80401
80402
80403             var watcher;
80404             watcher = window.setInterval(function () {
80405               if (context.container().select('div.combobox').empty()) {
80406                 window.clearInterval(watcher);
80407                 timeout(function () {
80408                   if (context.container().select('.form-field-description').empty()) {
80409                     continueTo(retryChooseDescription);
80410                   } else {
80411                     continueTo(describePlayground);
80412                   }
80413                 }, 300); // after description field added.
80414               }
80415             }, 300);
80416             reveal('div.combobox', helpHtml('intro.areas.choose_field', {
80417               field: descriptionField.label()
80418             }), {
80419               duration: 300
80420             });
80421             context.on('exit.intro', function () {
80422               return continueTo(searchPresets);
80423             });
80424
80425             function continueTo(nextStep) {
80426               if (watcher) window.clearInterval(watcher);
80427               context.on('exit.intro', null);
80428               nextStep();
80429             }
80430           }
80431
80432           function describePlayground() {
80433             if (!_areaID || !context.hasEntity(_areaID)) {
80434               return addArea();
80435             }
80436
80437             var ids = context.selectedIDs();
80438
80439             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
80440               return searchPresets();
80441             } // reset pane, in case user happened to change it..
80442
80443
80444             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
80445
80446             if (context.container().select('.form-field-description').empty()) {
80447               return continueTo(retryChooseDescription);
80448             }
80449
80450             context.on('exit.intro', function () {
80451               continueTo(play);
80452             });
80453             reveal('.entity-editor-pane', helpHtml('intro.areas.describe_playground', {
80454               button: icon('#iD-icon-close', 'inline')
80455             }), {
80456               duration: 300
80457             });
80458
80459             function continueTo(nextStep) {
80460               context.on('exit.intro', null);
80461               nextStep();
80462             }
80463           }
80464
80465           function retryChooseDescription() {
80466             if (!_areaID || !context.hasEntity(_areaID)) {
80467               return addArea();
80468             }
80469
80470             var ids = context.selectedIDs();
80471
80472             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
80473               return searchPresets();
80474             } // reset pane, in case user happened to change it..
80475
80476
80477             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
80478             reveal('.entity-editor-pane', helpHtml('intro.areas.retry_add_field', {
80479               field: descriptionField.label()
80480             }), {
80481               buttonText: _t.html('intro.ok'),
80482               buttonCallback: function buttonCallback() {
80483                 continueTo(clickAddField);
80484               }
80485             });
80486             context.on('exit.intro', function () {
80487               return continueTo(searchPresets);
80488             });
80489
80490             function continueTo(nextStep) {
80491               context.on('exit.intro', null);
80492               nextStep();
80493             }
80494           }
80495
80496           function play() {
80497             dispatch$1.call('done');
80498             reveal('.ideditor', helpHtml('intro.areas.play', {
80499               next: _t('intro.lines.title')
80500             }), {
80501               tooltipBox: '.intro-nav-wrap .chapter-line',
80502               buttonText: _t.html('intro.ok'),
80503               buttonCallback: function buttonCallback() {
80504                 reveal('.ideditor');
80505               }
80506             });
80507           }
80508
80509           chapter.enter = function () {
80510             addArea();
80511           };
80512
80513           chapter.exit = function () {
80514             timeouts.forEach(window.clearTimeout);
80515             context.on('enter.intro exit.intro', null);
80516             context.map().on('move.intro drawn.intro', null);
80517             context.history().on('change.intro', null);
80518             context.container().select('.inspector-wrap').on('wheel.intro', null);
80519             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
80520             context.container().select('.more-fields .combobox-input').on('click.intro', null);
80521           };
80522
80523           chapter.restart = function () {
80524             chapter.exit();
80525             chapter.enter();
80526           };
80527
80528           return utilRebind(chapter, dispatch$1, 'on');
80529         }
80530
80531         function uiIntroLine(context, reveal) {
80532           var dispatch$1 = dispatch('done');
80533           var timeouts = [];
80534           var _tulipRoadID = null;
80535           var flowerRoadID = 'w646';
80536           var tulipRoadStart = [-85.6297754121684, 41.95805253325314];
80537           var tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204];
80538           var tulipRoadIntersection = [-85.62974496187628, 41.95742515554585];
80539           var roadCategory = _mainPresetIndex.item('category-road_minor');
80540           var residentialPreset = _mainPresetIndex.item('highway/residential');
80541           var woodRoadID = 'w525';
80542           var woodRoadEndID = 'n2862';
80543           var woodRoadAddNode = [-85.62390110349587, 41.95397111462291];
80544           var woodRoadDragEndpoint = [-85.623867390213, 41.95466987786487];
80545           var woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872];
80546           var washingtonStreetID = 'w522';
80547           var twelfthAvenueID = 'w1';
80548           var eleventhAvenueEndID = 'n3550';
80549           var twelfthAvenueEndID = 'n5';
80550           var _washingtonSegmentID = null;
80551           var eleventhAvenueEnd = context.entity(eleventhAvenueEndID).loc;
80552           var twelfthAvenueEnd = context.entity(twelfthAvenueEndID).loc;
80553           var deleteLinesLoc = [-85.6219395542764, 41.95228033922477];
80554           var twelfthAvenue = [-85.62219310052491, 41.952505413152956];
80555           var chapter = {
80556             title: 'intro.lines.title'
80557           };
80558
80559           function timeout(f, t) {
80560             timeouts.push(window.setTimeout(f, t));
80561           }
80562
80563           function eventCancel(d3_event) {
80564             d3_event.stopPropagation();
80565             d3_event.preventDefault();
80566           }
80567
80568           function addLine() {
80569             context.enter(modeBrowse(context));
80570             context.history().reset('initial');
80571             var msec = transitionTime(tulipRoadStart, context.map().center());
80572
80573             if (msec) {
80574               reveal(null, null, {
80575                 duration: 0
80576               });
80577             }
80578
80579             context.map().centerZoomEase(tulipRoadStart, 18.5, msec);
80580             timeout(function () {
80581               var tooltip = reveal('button.add-line', helpHtml('intro.lines.add_line'));
80582               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-lines');
80583               context.on('enter.intro', function (mode) {
80584                 if (mode.id !== 'add-line') return;
80585                 continueTo(startLine);
80586               });
80587             }, msec + 100);
80588
80589             function continueTo(nextStep) {
80590               context.on('enter.intro', null);
80591               nextStep();
80592             }
80593           }
80594
80595           function startLine() {
80596             if (context.mode().id !== 'add-line') return chapter.restart();
80597             _tulipRoadID = null;
80598             var padding = 70 * Math.pow(2, context.map().zoom() - 18);
80599             var box = pad(tulipRoadStart, padding, context);
80600             box.height = box.height + 100;
80601             var textId = context.lastPointerType() === 'mouse' ? 'start_line' : 'start_line_tap';
80602             var startLineString = helpHtml('intro.lines.missing_road') + '{br}' + helpHtml('intro.lines.line_draw_info') + helpHtml('intro.lines.' + textId);
80603             reveal(box, startLineString);
80604             context.map().on('move.intro drawn.intro', function () {
80605               padding = 70 * Math.pow(2, context.map().zoom() - 18);
80606               box = pad(tulipRoadStart, padding, context);
80607               box.height = box.height + 100;
80608               reveal(box, startLineString, {
80609                 duration: 0
80610               });
80611             });
80612             context.on('enter.intro', function (mode) {
80613               if (mode.id !== 'draw-line') return chapter.restart();
80614               continueTo(drawLine);
80615             });
80616
80617             function continueTo(nextStep) {
80618               context.map().on('move.intro drawn.intro', null);
80619               context.on('enter.intro', null);
80620               nextStep();
80621             }
80622           }
80623
80624           function drawLine() {
80625             if (context.mode().id !== 'draw-line') return chapter.restart();
80626             _tulipRoadID = context.mode().selectedIDs()[0];
80627             context.map().centerEase(tulipRoadMidpoint, 500);
80628             timeout(function () {
80629               var padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
80630               var box = pad(tulipRoadMidpoint, padding, context);
80631               box.height = box.height * 2;
80632               reveal(box, helpHtml('intro.lines.intersect', {
80633                 name: _t('intro.graph.name.flower-street')
80634               }));
80635               context.map().on('move.intro drawn.intro', function () {
80636                 padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
80637                 box = pad(tulipRoadMidpoint, padding, context);
80638                 box.height = box.height * 2;
80639                 reveal(box, helpHtml('intro.lines.intersect', {
80640                   name: _t('intro.graph.name.flower-street')
80641                 }), {
80642                   duration: 0
80643                 });
80644               });
80645             }, 550); // after easing..
80646
80647             context.history().on('change.intro', function () {
80648               if (isLineConnected()) {
80649                 continueTo(continueLine);
80650               }
80651             });
80652             context.on('enter.intro', function (mode) {
80653               if (mode.id === 'draw-line') {
80654                 return;
80655               } else if (mode.id === 'select') {
80656                 continueTo(retryIntersect);
80657                 return;
80658               } else {
80659                 return chapter.restart();
80660               }
80661             });
80662
80663             function continueTo(nextStep) {
80664               context.map().on('move.intro drawn.intro', null);
80665               context.history().on('change.intro', null);
80666               context.on('enter.intro', null);
80667               nextStep();
80668             }
80669           }
80670
80671           function isLineConnected() {
80672             var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
80673
80674             if (!entity) return false;
80675             var drawNodes = context.graph().childNodes(entity);
80676             return drawNodes.some(function (node) {
80677               return context.graph().parentWays(node).some(function (parent) {
80678                 return parent.id === flowerRoadID;
80679               });
80680             });
80681           }
80682
80683           function retryIntersect() {
80684             select(window).on('pointerdown.intro mousedown.intro', eventCancel, true);
80685             var box = pad(tulipRoadIntersection, 80, context);
80686             reveal(box, helpHtml('intro.lines.retry_intersect', {
80687               name: _t('intro.graph.name.flower-street')
80688             }));
80689             timeout(chapter.restart, 3000);
80690           }
80691
80692           function continueLine() {
80693             if (context.mode().id !== 'draw-line') return chapter.restart();
80694
80695             var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
80696
80697             if (!entity) return chapter.restart();
80698             context.map().centerEase(tulipRoadIntersection, 500);
80699             var continueLineText = helpHtml('intro.lines.continue_line') + '{br}' + helpHtml('intro.lines.finish_line_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.lines.finish_road');
80700             reveal('.surface', continueLineText);
80701             context.on('enter.intro', function (mode) {
80702               if (mode.id === 'draw-line') return;else if (mode.id === 'select') return continueTo(chooseCategoryRoad);else return chapter.restart();
80703             });
80704
80705             function continueTo(nextStep) {
80706               context.on('enter.intro', null);
80707               nextStep();
80708             }
80709           }
80710
80711           function chooseCategoryRoad() {
80712             if (context.mode().id !== 'select') return chapter.restart();
80713             context.on('exit.intro', function () {
80714               return chapter.restart();
80715             });
80716             var button = context.container().select('.preset-category-road_minor .preset-list-button');
80717             if (button.empty()) return chapter.restart(); // disallow scrolling
80718
80719             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80720             timeout(function () {
80721               // reset pane, in case user somehow happened to change it..
80722               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
80723               reveal(button.node(), helpHtml('intro.lines.choose_category_road', {
80724                 category: roadCategory.name()
80725               }));
80726               button.on('click.intro', function () {
80727                 continueTo(choosePresetResidential);
80728               });
80729             }, 400); // after editor pane visible
80730
80731             function continueTo(nextStep) {
80732               context.container().select('.inspector-wrap').on('wheel.intro', null);
80733               context.container().select('.preset-list-button').on('click.intro', null);
80734               context.on('exit.intro', null);
80735               nextStep();
80736             }
80737           }
80738
80739           function choosePresetResidential() {
80740             if (context.mode().id !== 'select') return chapter.restart();
80741             context.on('exit.intro', function () {
80742               return chapter.restart();
80743             });
80744             var subgrid = context.container().select('.preset-category-road_minor .subgrid');
80745             if (subgrid.empty()) return chapter.restart();
80746             subgrid.selectAll(':not(.preset-highway-residential) .preset-list-button').on('click.intro', function () {
80747               continueTo(retryPresetResidential);
80748             });
80749             subgrid.selectAll('.preset-highway-residential .preset-list-button').on('click.intro', function () {
80750               continueTo(nameRoad);
80751             });
80752             timeout(function () {
80753               reveal(subgrid.node(), helpHtml('intro.lines.choose_preset_residential', {
80754                 preset: residentialPreset.name()
80755               }), {
80756                 tooltipBox: '.preset-highway-residential .preset-list-button',
80757                 duration: 300
80758               });
80759             }, 300);
80760
80761             function continueTo(nextStep) {
80762               context.container().select('.preset-list-button').on('click.intro', null);
80763               context.on('exit.intro', null);
80764               nextStep();
80765             }
80766           } // selected wrong road type
80767
80768
80769           function retryPresetResidential() {
80770             if (context.mode().id !== 'select') return chapter.restart();
80771             context.on('exit.intro', function () {
80772               return chapter.restart();
80773             }); // disallow scrolling
80774
80775             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80776             timeout(function () {
80777               var button = context.container().select('.entity-editor-pane .preset-list-button');
80778               reveal(button.node(), helpHtml('intro.lines.retry_preset_residential', {
80779                 preset: residentialPreset.name()
80780               }));
80781               button.on('click.intro', function () {
80782                 continueTo(chooseCategoryRoad);
80783               });
80784             }, 500);
80785
80786             function continueTo(nextStep) {
80787               context.container().select('.inspector-wrap').on('wheel.intro', null);
80788               context.container().select('.preset-list-button').on('click.intro', null);
80789               context.on('exit.intro', null);
80790               nextStep();
80791             }
80792           }
80793
80794           function nameRoad() {
80795             context.on('exit.intro', function () {
80796               continueTo(didNameRoad);
80797             });
80798             timeout(function () {
80799               reveal('.entity-editor-pane', helpHtml('intro.lines.name_road', {
80800                 button: icon('#iD-icon-close', 'inline')
80801               }), {
80802                 tooltipClass: 'intro-lines-name_road'
80803               });
80804             }, 500);
80805
80806             function continueTo(nextStep) {
80807               context.on('exit.intro', null);
80808               nextStep();
80809             }
80810           }
80811
80812           function didNameRoad() {
80813             context.history().checkpoint('doneAddLine');
80814             timeout(function () {
80815               reveal('.surface', helpHtml('intro.lines.did_name_road'), {
80816                 buttonText: _t.html('intro.ok'),
80817                 buttonCallback: function buttonCallback() {
80818                   continueTo(updateLine);
80819                 }
80820               });
80821             }, 500);
80822
80823             function continueTo(nextStep) {
80824               nextStep();
80825             }
80826           }
80827
80828           function updateLine() {
80829             context.history().reset('doneAddLine');
80830
80831             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80832               return chapter.restart();
80833             }
80834
80835             var msec = transitionTime(woodRoadDragMidpoint, context.map().center());
80836
80837             if (msec) {
80838               reveal(null, null, {
80839                 duration: 0
80840               });
80841             }
80842
80843             context.map().centerZoomEase(woodRoadDragMidpoint, 19, msec);
80844             timeout(function () {
80845               var padding = 250 * Math.pow(2, context.map().zoom() - 19);
80846               var box = pad(woodRoadDragMidpoint, padding, context);
80847
80848               var advance = function advance() {
80849                 continueTo(addNode);
80850               };
80851
80852               reveal(box, helpHtml('intro.lines.update_line'), {
80853                 buttonText: _t.html('intro.ok'),
80854                 buttonCallback: advance
80855               });
80856               context.map().on('move.intro drawn.intro', function () {
80857                 var padding = 250 * Math.pow(2, context.map().zoom() - 19);
80858                 var box = pad(woodRoadDragMidpoint, padding, context);
80859                 reveal(box, helpHtml('intro.lines.update_line'), {
80860                   duration: 0,
80861                   buttonText: _t.html('intro.ok'),
80862                   buttonCallback: advance
80863                 });
80864               });
80865             }, msec + 100);
80866
80867             function continueTo(nextStep) {
80868               context.map().on('move.intro drawn.intro', null);
80869               nextStep();
80870             }
80871           }
80872
80873           function addNode() {
80874             context.history().reset('doneAddLine');
80875
80876             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80877               return chapter.restart();
80878             }
80879
80880             var padding = 40 * Math.pow(2, context.map().zoom() - 19);
80881             var box = pad(woodRoadAddNode, padding, context);
80882             var addNodeString = helpHtml('intro.lines.add_node' + (context.lastPointerType() === 'mouse' ? '' : '_touch'));
80883             reveal(box, addNodeString);
80884             context.map().on('move.intro drawn.intro', function () {
80885               var padding = 40 * Math.pow(2, context.map().zoom() - 19);
80886               var box = pad(woodRoadAddNode, padding, context);
80887               reveal(box, addNodeString, {
80888                 duration: 0
80889               });
80890             });
80891             context.history().on('change.intro', function (changed) {
80892               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80893                 return continueTo(updateLine);
80894               }
80895
80896               if (changed.created().length === 1) {
80897                 timeout(function () {
80898                   continueTo(startDragEndpoint);
80899                 }, 500);
80900               }
80901             });
80902             context.on('enter.intro', function (mode) {
80903               if (mode.id !== 'select') {
80904                 continueTo(updateLine);
80905               }
80906             });
80907
80908             function continueTo(nextStep) {
80909               context.map().on('move.intro drawn.intro', null);
80910               context.history().on('change.intro', null);
80911               context.on('enter.intro', null);
80912               nextStep();
80913             }
80914           }
80915
80916           function startDragEndpoint() {
80917             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80918               return continueTo(updateLine);
80919             }
80920
80921             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80922             var box = pad(woodRoadDragEndpoint, padding, context);
80923             var startDragString = helpHtml('intro.lines.start_drag_endpoint' + (context.lastPointerType() === 'mouse' ? '' : '_touch')) + helpHtml('intro.lines.drag_to_intersection');
80924             reveal(box, startDragString);
80925             context.map().on('move.intro drawn.intro', function () {
80926               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80927                 return continueTo(updateLine);
80928               }
80929
80930               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80931               var box = pad(woodRoadDragEndpoint, padding, context);
80932               reveal(box, startDragString, {
80933                 duration: 0
80934               });
80935               var entity = context.entity(woodRoadEndID);
80936
80937               if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) <= 4) {
80938                 continueTo(finishDragEndpoint);
80939               }
80940             });
80941
80942             function continueTo(nextStep) {
80943               context.map().on('move.intro drawn.intro', null);
80944               nextStep();
80945             }
80946           }
80947
80948           function finishDragEndpoint() {
80949             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80950               return continueTo(updateLine);
80951             }
80952
80953             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80954             var box = pad(woodRoadDragEndpoint, padding, context);
80955             var finishDragString = helpHtml('intro.lines.spot_looks_good') + helpHtml('intro.lines.finish_drag_endpoint' + (context.lastPointerType() === 'mouse' ? '' : '_touch'));
80956             reveal(box, finishDragString);
80957             context.map().on('move.intro drawn.intro', function () {
80958               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80959                 return continueTo(updateLine);
80960               }
80961
80962               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80963               var box = pad(woodRoadDragEndpoint, padding, context);
80964               reveal(box, finishDragString, {
80965                 duration: 0
80966               });
80967               var entity = context.entity(woodRoadEndID);
80968
80969               if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) > 4) {
80970                 continueTo(startDragEndpoint);
80971               }
80972             });
80973             context.on('enter.intro', function () {
80974               continueTo(startDragMidpoint);
80975             });
80976
80977             function continueTo(nextStep) {
80978               context.map().on('move.intro drawn.intro', null);
80979               context.on('enter.intro', null);
80980               nextStep();
80981             }
80982           }
80983
80984           function startDragMidpoint() {
80985             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80986               return continueTo(updateLine);
80987             }
80988
80989             if (context.selectedIDs().indexOf(woodRoadID) === -1) {
80990               context.enter(modeSelect(context, [woodRoadID]));
80991             }
80992
80993             var padding = 80 * Math.pow(2, context.map().zoom() - 19);
80994             var box = pad(woodRoadDragMidpoint, padding, context);
80995             reveal(box, helpHtml('intro.lines.start_drag_midpoint'));
80996             context.map().on('move.intro drawn.intro', function () {
80997               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80998                 return continueTo(updateLine);
80999               }
81000
81001               var padding = 80 * Math.pow(2, context.map().zoom() - 19);
81002               var box = pad(woodRoadDragMidpoint, padding, context);
81003               reveal(box, helpHtml('intro.lines.start_drag_midpoint'), {
81004                 duration: 0
81005               });
81006             });
81007             context.history().on('change.intro', function (changed) {
81008               if (changed.created().length === 1) {
81009                 continueTo(continueDragMidpoint);
81010               }
81011             });
81012             context.on('enter.intro', function (mode) {
81013               if (mode.id !== 'select') {
81014                 // keep Wood Road selected so midpoint triangles are drawn..
81015                 context.enter(modeSelect(context, [woodRoadID]));
81016               }
81017             });
81018
81019             function continueTo(nextStep) {
81020               context.map().on('move.intro drawn.intro', null);
81021               context.history().on('change.intro', null);
81022               context.on('enter.intro', null);
81023               nextStep();
81024             }
81025           }
81026
81027           function continueDragMidpoint() {
81028             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
81029               return continueTo(updateLine);
81030             }
81031
81032             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
81033             var box = pad(woodRoadDragEndpoint, padding, context);
81034             box.height += 400;
81035
81036             var advance = function advance() {
81037               context.history().checkpoint('doneUpdateLine');
81038               continueTo(deleteLines);
81039             };
81040
81041             reveal(box, helpHtml('intro.lines.continue_drag_midpoint'), {
81042               buttonText: _t.html('intro.ok'),
81043               buttonCallback: advance
81044             });
81045             context.map().on('move.intro drawn.intro', function () {
81046               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
81047                 return continueTo(updateLine);
81048               }
81049
81050               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
81051               var box = pad(woodRoadDragEndpoint, padding, context);
81052               box.height += 400;
81053               reveal(box, helpHtml('intro.lines.continue_drag_midpoint'), {
81054                 duration: 0,
81055                 buttonText: _t.html('intro.ok'),
81056                 buttonCallback: advance
81057               });
81058             });
81059
81060             function continueTo(nextStep) {
81061               context.map().on('move.intro drawn.intro', null);
81062               nextStep();
81063             }
81064           }
81065
81066           function deleteLines() {
81067             context.history().reset('doneUpdateLine');
81068             context.enter(modeBrowse(context));
81069
81070             if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81071               return chapter.restart();
81072             }
81073
81074             var msec = transitionTime(deleteLinesLoc, context.map().center());
81075
81076             if (msec) {
81077               reveal(null, null, {
81078                 duration: 0
81079               });
81080             }
81081
81082             context.map().centerZoomEase(deleteLinesLoc, 18, msec);
81083             timeout(function () {
81084               var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81085               var box = pad(deleteLinesLoc, padding, context);
81086               box.top -= 200;
81087               box.height += 400;
81088
81089               var advance = function advance() {
81090                 continueTo(rightClickIntersection);
81091               };
81092
81093               reveal(box, helpHtml('intro.lines.delete_lines', {
81094                 street: _t('intro.graph.name.12th-avenue')
81095               }), {
81096                 buttonText: _t.html('intro.ok'),
81097                 buttonCallback: advance
81098               });
81099               context.map().on('move.intro drawn.intro', function () {
81100                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81101                 var box = pad(deleteLinesLoc, padding, context);
81102                 box.top -= 200;
81103                 box.height += 400;
81104                 reveal(box, helpHtml('intro.lines.delete_lines', {
81105                   street: _t('intro.graph.name.12th-avenue')
81106                 }), {
81107                   duration: 0,
81108                   buttonText: _t.html('intro.ok'),
81109                   buttonCallback: advance
81110                 });
81111               });
81112               context.history().on('change.intro', function () {
81113                 timeout(function () {
81114                   continueTo(deleteLines);
81115                 }, 500); // after any transition (e.g. if user deleted intersection)
81116               });
81117             }, msec + 100);
81118
81119             function continueTo(nextStep) {
81120               context.map().on('move.intro drawn.intro', null);
81121               context.history().on('change.intro', null);
81122               nextStep();
81123             }
81124           }
81125
81126           function rightClickIntersection() {
81127             context.history().reset('doneUpdateLine');
81128             context.enter(modeBrowse(context));
81129             context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
81130             var rightClickString = helpHtml('intro.lines.split_street', {
81131               street1: _t('intro.graph.name.11th-avenue'),
81132               street2: _t('intro.graph.name.washington-street')
81133             }) + helpHtml('intro.lines.' + (context.lastPointerType() === 'mouse' ? 'rightclick_intersection' : 'edit_menu_intersection_touch'));
81134             timeout(function () {
81135               var padding = 60 * Math.pow(2, context.map().zoom() - 18);
81136               var box = pad(eleventhAvenueEnd, padding, context);
81137               reveal(box, rightClickString);
81138               context.map().on('move.intro drawn.intro', function () {
81139                 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
81140                 var box = pad(eleventhAvenueEnd, padding, context);
81141                 reveal(box, rightClickString, {
81142                   duration: 0
81143                 });
81144               });
81145               context.on('enter.intro', function (mode) {
81146                 if (mode.id !== 'select') return;
81147                 var ids = context.selectedIDs();
81148                 if (ids.length !== 1 || ids[0] !== eleventhAvenueEndID) return;
81149                 timeout(function () {
81150                   var node = selectMenuItem(context, 'split').node();
81151                   if (!node) return;
81152                   continueTo(splitIntersection);
81153                 }, 50); // after menu visible
81154               });
81155               context.history().on('change.intro', function () {
81156                 timeout(function () {
81157                   continueTo(deleteLines);
81158                 }, 300); // after any transition (e.g. if user deleted intersection)
81159               });
81160             }, 600);
81161
81162             function continueTo(nextStep) {
81163               context.map().on('move.intro drawn.intro', null);
81164               context.on('enter.intro', null);
81165               context.history().on('change.intro', null);
81166               nextStep();
81167             }
81168           }
81169
81170           function splitIntersection() {
81171             if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81172               return continueTo(deleteLines);
81173             }
81174
81175             var node = selectMenuItem(context, 'split').node();
81176
81177             if (!node) {
81178               return continueTo(rightClickIntersection);
81179             }
81180
81181             var wasChanged = false;
81182             _washingtonSegmentID = null;
81183             reveal('.edit-menu', helpHtml('intro.lines.split_intersection', {
81184               street: _t('intro.graph.name.washington-street')
81185             }), {
81186               padding: 50
81187             });
81188             context.map().on('move.intro drawn.intro', function () {
81189               var node = selectMenuItem(context, 'split').node();
81190
81191               if (!wasChanged && !node) {
81192                 return continueTo(rightClickIntersection);
81193               }
81194
81195               reveal('.edit-menu', helpHtml('intro.lines.split_intersection', {
81196                 street: _t('intro.graph.name.washington-street')
81197               }), {
81198                 duration: 0,
81199                 padding: 50
81200               });
81201             });
81202             context.history().on('change.intro', function (changed) {
81203               wasChanged = true;
81204               timeout(function () {
81205                 if (context.history().undoAnnotation() === _t('operations.split.annotation.line', {
81206                   n: 1
81207                 })) {
81208                   _washingtonSegmentID = changed.created()[0].id;
81209                   continueTo(didSplit);
81210                 } else {
81211                   _washingtonSegmentID = null;
81212                   continueTo(retrySplit);
81213                 }
81214               }, 300); // after any transition (e.g. if user deleted intersection)
81215             });
81216
81217             function continueTo(nextStep) {
81218               context.map().on('move.intro drawn.intro', null);
81219               context.history().on('change.intro', null);
81220               nextStep();
81221             }
81222           }
81223
81224           function retrySplit() {
81225             context.enter(modeBrowse(context));
81226             context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
81227
81228             var advance = function advance() {
81229               continueTo(rightClickIntersection);
81230             };
81231
81232             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
81233             var box = pad(eleventhAvenueEnd, padding, context);
81234             reveal(box, helpHtml('intro.lines.retry_split'), {
81235               buttonText: _t.html('intro.ok'),
81236               buttonCallback: advance
81237             });
81238             context.map().on('move.intro drawn.intro', function () {
81239               var padding = 60 * Math.pow(2, context.map().zoom() - 18);
81240               var box = pad(eleventhAvenueEnd, padding, context);
81241               reveal(box, helpHtml('intro.lines.retry_split'), {
81242                 duration: 0,
81243                 buttonText: _t.html('intro.ok'),
81244                 buttonCallback: advance
81245               });
81246             });
81247
81248             function continueTo(nextStep) {
81249               context.map().on('move.intro drawn.intro', null);
81250               nextStep();
81251             }
81252           }
81253
81254           function didSplit() {
81255             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81256               return continueTo(rightClickIntersection);
81257             }
81258
81259             var ids = context.selectedIDs();
81260             var string = 'intro.lines.did_split_' + (ids.length > 1 ? 'multi' : 'single');
81261             var street = _t('intro.graph.name.washington-street');
81262             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81263             var box = pad(twelfthAvenue, padding, context);
81264             box.width = box.width / 2;
81265             reveal(box, helpHtml(string, {
81266               street1: street,
81267               street2: street
81268             }), {
81269               duration: 500
81270             });
81271             timeout(function () {
81272               context.map().centerZoomEase(twelfthAvenue, 18, 500);
81273               context.map().on('move.intro drawn.intro', function () {
81274                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81275                 var box = pad(twelfthAvenue, padding, context);
81276                 box.width = box.width / 2;
81277                 reveal(box, helpHtml(string, {
81278                   street1: street,
81279                   street2: street
81280                 }), {
81281                   duration: 0
81282                 });
81283               });
81284             }, 600); // after initial reveal and curtain cut
81285
81286             context.on('enter.intro', function () {
81287               var ids = context.selectedIDs();
81288
81289               if (ids.length === 1 && ids[0] === _washingtonSegmentID) {
81290                 continueTo(multiSelect);
81291               }
81292             });
81293             context.history().on('change.intro', function () {
81294               if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81295                 return continueTo(rightClickIntersection);
81296               }
81297             });
81298
81299             function continueTo(nextStep) {
81300               context.map().on('move.intro drawn.intro', null);
81301               context.on('enter.intro', null);
81302               context.history().on('change.intro', null);
81303               nextStep();
81304             }
81305           }
81306
81307           function multiSelect() {
81308             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81309               return continueTo(rightClickIntersection);
81310             }
81311
81312             var ids = context.selectedIDs();
81313             var hasWashington = ids.indexOf(_washingtonSegmentID) !== -1;
81314             var hasTwelfth = ids.indexOf(twelfthAvenueID) !== -1;
81315
81316             if (hasWashington && hasTwelfth) {
81317               return continueTo(multiRightClick);
81318             } else if (!hasWashington && !hasTwelfth) {
81319               return continueTo(didSplit);
81320             }
81321
81322             context.map().centerZoomEase(twelfthAvenue, 18, 500);
81323             timeout(function () {
81324               var selected, other, padding, box;
81325
81326               if (hasWashington) {
81327                 selected = _t('intro.graph.name.washington-street');
81328                 other = _t('intro.graph.name.12th-avenue');
81329                 padding = 60 * Math.pow(2, context.map().zoom() - 18);
81330                 box = pad(twelfthAvenueEnd, padding, context);
81331                 box.width *= 3;
81332               } else {
81333                 selected = _t('intro.graph.name.12th-avenue');
81334                 other = _t('intro.graph.name.washington-street');
81335                 padding = 200 * Math.pow(2, context.map().zoom() - 18);
81336                 box = pad(twelfthAvenue, padding, context);
81337                 box.width /= 2;
81338               }
81339
81340               reveal(box, helpHtml('intro.lines.multi_select', {
81341                 selected: selected,
81342                 other1: other
81343               }) + ' ' + helpHtml('intro.lines.add_to_selection_' + (context.lastPointerType() === 'mouse' ? 'click' : 'touch'), {
81344                 selected: selected,
81345                 other2: other
81346               }));
81347               context.map().on('move.intro drawn.intro', function () {
81348                 if (hasWashington) {
81349                   selected = _t('intro.graph.name.washington-street');
81350                   other = _t('intro.graph.name.12th-avenue');
81351                   padding = 60 * Math.pow(2, context.map().zoom() - 18);
81352                   box = pad(twelfthAvenueEnd, padding, context);
81353                   box.width *= 3;
81354                 } else {
81355                   selected = _t('intro.graph.name.12th-avenue');
81356                   other = _t('intro.graph.name.washington-street');
81357                   padding = 200 * Math.pow(2, context.map().zoom() - 18);
81358                   box = pad(twelfthAvenue, padding, context);
81359                   box.width /= 2;
81360                 }
81361
81362                 reveal(box, helpHtml('intro.lines.multi_select', {
81363                   selected: selected,
81364                   other1: other
81365                 }) + ' ' + helpHtml('intro.lines.add_to_selection_' + (context.lastPointerType() === 'mouse' ? 'click' : 'touch'), {
81366                   selected: selected,
81367                   other2: other
81368                 }), {
81369                   duration: 0
81370                 });
81371               });
81372               context.on('enter.intro', function () {
81373                 continueTo(multiSelect);
81374               });
81375               context.history().on('change.intro', function () {
81376                 if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81377                   return continueTo(rightClickIntersection);
81378                 }
81379               });
81380             }, 600);
81381
81382             function continueTo(nextStep) {
81383               context.map().on('move.intro drawn.intro', null);
81384               context.on('enter.intro', null);
81385               context.history().on('change.intro', null);
81386               nextStep();
81387             }
81388           }
81389
81390           function multiRightClick() {
81391             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81392               return continueTo(rightClickIntersection);
81393             }
81394
81395             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81396             var box = pad(twelfthAvenue, padding, context);
81397             var rightClickString = helpHtml('intro.lines.multi_select_success') + helpHtml('intro.lines.multi_' + (context.lastPointerType() === 'mouse' ? 'rightclick' : 'edit_menu_touch'));
81398             reveal(box, rightClickString);
81399             context.map().on('move.intro drawn.intro', function () {
81400               var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81401               var box = pad(twelfthAvenue, padding, context);
81402               reveal(box, rightClickString, {
81403                 duration: 0
81404               });
81405             });
81406             context.ui().editMenu().on('toggled.intro', function (open) {
81407               if (!open) return;
81408               timeout(function () {
81409                 var ids = context.selectedIDs();
81410
81411                 if (ids.length === 2 && ids.indexOf(twelfthAvenueID) !== -1 && ids.indexOf(_washingtonSegmentID) !== -1) {
81412                   var node = selectMenuItem(context, 'delete').node();
81413                   if (!node) return;
81414                   continueTo(multiDelete);
81415                 } else if (ids.length === 1 && ids.indexOf(_washingtonSegmentID) !== -1) {
81416                   return continueTo(multiSelect);
81417                 } else {
81418                   return continueTo(didSplit);
81419                 }
81420               }, 300); // after edit menu visible
81421             });
81422             context.history().on('change.intro', function () {
81423               if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81424                 return continueTo(rightClickIntersection);
81425               }
81426             });
81427
81428             function continueTo(nextStep) {
81429               context.map().on('move.intro drawn.intro', null);
81430               context.ui().editMenu().on('toggled.intro', null);
81431               context.history().on('change.intro', null);
81432               nextStep();
81433             }
81434           }
81435
81436           function multiDelete() {
81437             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81438               return continueTo(rightClickIntersection);
81439             }
81440
81441             var node = selectMenuItem(context, 'delete').node();
81442             if (!node) return continueTo(multiRightClick);
81443             reveal('.edit-menu', helpHtml('intro.lines.multi_delete'), {
81444               padding: 50
81445             });
81446             context.map().on('move.intro drawn.intro', function () {
81447               reveal('.edit-menu', helpHtml('intro.lines.multi_delete'), {
81448                 duration: 0,
81449                 padding: 50
81450               });
81451             });
81452             context.on('exit.intro', function () {
81453               if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
81454                 return continueTo(multiSelect); // left select mode but roads still exist
81455               }
81456             });
81457             context.history().on('change.intro', function () {
81458               if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
81459                 continueTo(retryDelete); // changed something but roads still exist
81460               } else {
81461                 continueTo(play);
81462               }
81463             });
81464
81465             function continueTo(nextStep) {
81466               context.map().on('move.intro drawn.intro', null);
81467               context.on('exit.intro', null);
81468               context.history().on('change.intro', null);
81469               nextStep();
81470             }
81471           }
81472
81473           function retryDelete() {
81474             context.enter(modeBrowse(context));
81475             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81476             var box = pad(twelfthAvenue, padding, context);
81477             reveal(box, helpHtml('intro.lines.retry_delete'), {
81478               buttonText: _t.html('intro.ok'),
81479               buttonCallback: function buttonCallback() {
81480                 continueTo(multiSelect);
81481               }
81482             });
81483
81484             function continueTo(nextStep) {
81485               nextStep();
81486             }
81487           }
81488
81489           function play() {
81490             dispatch$1.call('done');
81491             reveal('.ideditor', helpHtml('intro.lines.play', {
81492               next: _t('intro.buildings.title')
81493             }), {
81494               tooltipBox: '.intro-nav-wrap .chapter-building',
81495               buttonText: _t.html('intro.ok'),
81496               buttonCallback: function buttonCallback() {
81497                 reveal('.ideditor');
81498               }
81499             });
81500           }
81501
81502           chapter.enter = function () {
81503             addLine();
81504           };
81505
81506           chapter.exit = function () {
81507             timeouts.forEach(window.clearTimeout);
81508             select(window).on('pointerdown.intro mousedown.intro', null, true);
81509             context.on('enter.intro exit.intro', null);
81510             context.map().on('move.intro drawn.intro', null);
81511             context.history().on('change.intro', null);
81512             context.container().select('.inspector-wrap').on('wheel.intro', null);
81513             context.container().select('.preset-list-button').on('click.intro', null);
81514           };
81515
81516           chapter.restart = function () {
81517             chapter.exit();
81518             chapter.enter();
81519           };
81520
81521           return utilRebind(chapter, dispatch$1, 'on');
81522         }
81523
81524         function uiIntroBuilding(context, reveal) {
81525           var dispatch$1 = dispatch('done');
81526           var house = [-85.62815, 41.95638];
81527           var tank = [-85.62732, 41.95347];
81528           var buildingCatetory = _mainPresetIndex.item('category-building');
81529           var housePreset = _mainPresetIndex.item('building/house');
81530           var tankPreset = _mainPresetIndex.item('man_made/storage_tank');
81531           var timeouts = [];
81532           var _houseID = null;
81533           var _tankID = null;
81534           var chapter = {
81535             title: 'intro.buildings.title'
81536           };
81537
81538           function timeout(f, t) {
81539             timeouts.push(window.setTimeout(f, t));
81540           }
81541
81542           function eventCancel(d3_event) {
81543             d3_event.stopPropagation();
81544             d3_event.preventDefault();
81545           }
81546
81547           function revealHouse(center, text, options) {
81548             var padding = 160 * Math.pow(2, context.map().zoom() - 20);
81549             var box = pad(center, padding, context);
81550             reveal(box, text, options);
81551           }
81552
81553           function revealTank(center, text, options) {
81554             var padding = 190 * Math.pow(2, context.map().zoom() - 19.5);
81555             var box = pad(center, padding, context);
81556             reveal(box, text, options);
81557           }
81558
81559           function addHouse() {
81560             context.enter(modeBrowse(context));
81561             context.history().reset('initial');
81562             _houseID = null;
81563             var msec = transitionTime(house, context.map().center());
81564
81565             if (msec) {
81566               reveal(null, null, {
81567                 duration: 0
81568               });
81569             }
81570
81571             context.map().centerZoomEase(house, 19, msec);
81572             timeout(function () {
81573               var tooltip = reveal('button.add-area', helpHtml('intro.buildings.add_building'));
81574               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-buildings');
81575               context.on('enter.intro', function (mode) {
81576                 if (mode.id !== 'add-area') return;
81577                 continueTo(startHouse);
81578               });
81579             }, msec + 100);
81580
81581             function continueTo(nextStep) {
81582               context.on('enter.intro', null);
81583               nextStep();
81584             }
81585           }
81586
81587           function startHouse() {
81588             if (context.mode().id !== 'add-area') {
81589               return continueTo(addHouse);
81590             }
81591
81592             _houseID = null;
81593             context.map().zoomEase(20, 500);
81594             timeout(function () {
81595               var startString = helpHtml('intro.buildings.start_building') + helpHtml('intro.buildings.building_corner_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap'));
81596               revealHouse(house, startString);
81597               context.map().on('move.intro drawn.intro', function () {
81598                 revealHouse(house, startString, {
81599                   duration: 0
81600                 });
81601               });
81602               context.on('enter.intro', function (mode) {
81603                 if (mode.id !== 'draw-area') return chapter.restart();
81604                 continueTo(continueHouse);
81605               });
81606             }, 550); // after easing
81607
81608             function continueTo(nextStep) {
81609               context.map().on('move.intro drawn.intro', null);
81610               context.on('enter.intro', null);
81611               nextStep();
81612             }
81613           }
81614
81615           function continueHouse() {
81616             if (context.mode().id !== 'draw-area') {
81617               return continueTo(addHouse);
81618             }
81619
81620             _houseID = null;
81621             var continueString = helpHtml('intro.buildings.continue_building') + '{br}' + helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.buildings.finish_building');
81622             revealHouse(house, continueString);
81623             context.map().on('move.intro drawn.intro', function () {
81624               revealHouse(house, continueString, {
81625                 duration: 0
81626               });
81627             });
81628             context.on('enter.intro', function (mode) {
81629               if (mode.id === 'draw-area') {
81630                 return;
81631               } else if (mode.id === 'select') {
81632                 var graph = context.graph();
81633                 var way = context.entity(context.selectedIDs()[0]);
81634                 var nodes = graph.childNodes(way);
81635                 var points = utilArrayUniq(nodes).map(function (n) {
81636                   return context.projection(n.loc);
81637                 });
81638
81639                 if (isMostlySquare(points)) {
81640                   _houseID = way.id;
81641                   return continueTo(chooseCategoryBuilding);
81642                 } else {
81643                   return continueTo(retryHouse);
81644                 }
81645               } else {
81646                 return chapter.restart();
81647               }
81648             });
81649
81650             function continueTo(nextStep) {
81651               context.map().on('move.intro drawn.intro', null);
81652               context.on('enter.intro', null);
81653               nextStep();
81654             }
81655           }
81656
81657           function retryHouse() {
81658             var onClick = function onClick() {
81659               continueTo(addHouse);
81660             };
81661
81662             revealHouse(house, helpHtml('intro.buildings.retry_building'), {
81663               buttonText: _t.html('intro.ok'),
81664               buttonCallback: onClick
81665             });
81666             context.map().on('move.intro drawn.intro', function () {
81667               revealHouse(house, helpHtml('intro.buildings.retry_building'), {
81668                 duration: 0,
81669                 buttonText: _t.html('intro.ok'),
81670                 buttonCallback: onClick
81671               });
81672             });
81673
81674             function continueTo(nextStep) {
81675               context.map().on('move.intro drawn.intro', null);
81676               nextStep();
81677             }
81678           }
81679
81680           function chooseCategoryBuilding() {
81681             if (!_houseID || !context.hasEntity(_houseID)) {
81682               return addHouse();
81683             }
81684
81685             var ids = context.selectedIDs();
81686
81687             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
81688               context.enter(modeSelect(context, [_houseID]));
81689             } // disallow scrolling
81690
81691
81692             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
81693             timeout(function () {
81694               // reset pane, in case user somehow happened to change it..
81695               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
81696               var button = context.container().select('.preset-category-building .preset-list-button');
81697               reveal(button.node(), helpHtml('intro.buildings.choose_category_building', {
81698                 category: buildingCatetory.name()
81699               }));
81700               button.on('click.intro', function () {
81701                 button.on('click.intro', null);
81702                 continueTo(choosePresetHouse);
81703               });
81704             }, 400); // after preset list pane visible..
81705
81706             context.on('enter.intro', function (mode) {
81707               if (!_houseID || !context.hasEntity(_houseID)) {
81708                 return continueTo(addHouse);
81709               }
81710
81711               var ids = context.selectedIDs();
81712
81713               if (mode.id !== 'select' || !ids.length || ids[0] !== _houseID) {
81714                 return continueTo(chooseCategoryBuilding);
81715               }
81716             });
81717
81718             function continueTo(nextStep) {
81719               context.container().select('.inspector-wrap').on('wheel.intro', null);
81720               context.container().select('.preset-list-button').on('click.intro', null);
81721               context.on('enter.intro', null);
81722               nextStep();
81723             }
81724           }
81725
81726           function choosePresetHouse() {
81727             if (!_houseID || !context.hasEntity(_houseID)) {
81728               return addHouse();
81729             }
81730
81731             var ids = context.selectedIDs();
81732
81733             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
81734               context.enter(modeSelect(context, [_houseID]));
81735             } // disallow scrolling
81736
81737
81738             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
81739             timeout(function () {
81740               // reset pane, in case user somehow happened to change it..
81741               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
81742               var button = context.container().select('.preset-building-house .preset-list-button');
81743               reveal(button.node(), helpHtml('intro.buildings.choose_preset_house', {
81744                 preset: housePreset.name()
81745               }), {
81746                 duration: 300
81747               });
81748               button.on('click.intro', function () {
81749                 button.on('click.intro', null);
81750                 continueTo(closeEditorHouse);
81751               });
81752             }, 400); // after preset list pane visible..
81753
81754             context.on('enter.intro', function (mode) {
81755               if (!_houseID || !context.hasEntity(_houseID)) {
81756                 return continueTo(addHouse);
81757               }
81758
81759               var ids = context.selectedIDs();
81760
81761               if (mode.id !== 'select' || !ids.length || ids[0] !== _houseID) {
81762                 return continueTo(chooseCategoryBuilding);
81763               }
81764             });
81765
81766             function continueTo(nextStep) {
81767               context.container().select('.inspector-wrap').on('wheel.intro', null);
81768               context.container().select('.preset-list-button').on('click.intro', null);
81769               context.on('enter.intro', null);
81770               nextStep();
81771             }
81772           }
81773
81774           function closeEditorHouse() {
81775             if (!_houseID || !context.hasEntity(_houseID)) {
81776               return addHouse();
81777             }
81778
81779             var ids = context.selectedIDs();
81780
81781             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
81782               context.enter(modeSelect(context, [_houseID]));
81783             }
81784
81785             context.history().checkpoint('hasHouse');
81786             context.on('exit.intro', function () {
81787               continueTo(rightClickHouse);
81788             });
81789             timeout(function () {
81790               reveal('.entity-editor-pane', helpHtml('intro.buildings.close', {
81791                 button: icon('#iD-icon-close', 'inline')
81792               }));
81793             }, 500);
81794
81795             function continueTo(nextStep) {
81796               context.on('exit.intro', null);
81797               nextStep();
81798             }
81799           }
81800
81801           function rightClickHouse() {
81802             if (!_houseID) return chapter.restart();
81803             context.enter(modeBrowse(context));
81804             context.history().reset('hasHouse');
81805             var zoom = context.map().zoom();
81806
81807             if (zoom < 20) {
81808               zoom = 20;
81809             }
81810
81811             context.map().centerZoomEase(house, zoom, 500);
81812             context.on('enter.intro', function (mode) {
81813               if (mode.id !== 'select') return;
81814               var ids = context.selectedIDs();
81815               if (ids.length !== 1 || ids[0] !== _houseID) return;
81816               timeout(function () {
81817                 var node = selectMenuItem(context, 'orthogonalize').node();
81818                 if (!node) return;
81819                 continueTo(clickSquare);
81820               }, 50); // after menu visible
81821             });
81822             context.map().on('move.intro drawn.intro', function () {
81823               var rightclickString = helpHtml('intro.buildings.' + (context.lastPointerType() === 'mouse' ? 'rightclick_building' : 'edit_menu_building_touch'));
81824               revealHouse(house, rightclickString, {
81825                 duration: 0
81826               });
81827             });
81828             context.history().on('change.intro', function () {
81829               continueTo(rightClickHouse);
81830             });
81831
81832             function continueTo(nextStep) {
81833               context.on('enter.intro', null);
81834               context.map().on('move.intro drawn.intro', null);
81835               context.history().on('change.intro', null);
81836               nextStep();
81837             }
81838           }
81839
81840           function clickSquare() {
81841             if (!_houseID) return chapter.restart();
81842             var entity = context.hasEntity(_houseID);
81843             if (!entity) return continueTo(rightClickHouse);
81844             var node = selectMenuItem(context, 'orthogonalize').node();
81845
81846             if (!node) {
81847               return continueTo(rightClickHouse);
81848             }
81849
81850             var wasChanged = false;
81851             reveal('.edit-menu', helpHtml('intro.buildings.square_building'), {
81852               padding: 50
81853             });
81854             context.on('enter.intro', function (mode) {
81855               if (mode.id === 'browse') {
81856                 continueTo(rightClickHouse);
81857               } else if (mode.id === 'move' || mode.id === 'rotate') {
81858                 continueTo(retryClickSquare);
81859               }
81860             });
81861             context.map().on('move.intro', function () {
81862               var node = selectMenuItem(context, 'orthogonalize').node();
81863
81864               if (!wasChanged && !node) {
81865                 return continueTo(rightClickHouse);
81866               }
81867
81868               reveal('.edit-menu', helpHtml('intro.buildings.square_building'), {
81869                 duration: 0,
81870                 padding: 50
81871               });
81872             });
81873             context.history().on('change.intro', function () {
81874               wasChanged = true;
81875               context.history().on('change.intro', null); // Something changed.  Wait for transition to complete and check undo annotation.
81876
81877               timeout(function () {
81878                 if (context.history().undoAnnotation() === _t('operations.orthogonalize.annotation.feature', {
81879                   n: 1
81880                 })) {
81881                   continueTo(doneSquare);
81882                 } else {
81883                   continueTo(retryClickSquare);
81884                 }
81885               }, 500); // after transitioned actions
81886             });
81887
81888             function continueTo(nextStep) {
81889               context.on('enter.intro', null);
81890               context.map().on('move.intro', null);
81891               context.history().on('change.intro', null);
81892               nextStep();
81893             }
81894           }
81895
81896           function retryClickSquare() {
81897             context.enter(modeBrowse(context));
81898             revealHouse(house, helpHtml('intro.buildings.retry_square'), {
81899               buttonText: _t.html('intro.ok'),
81900               buttonCallback: function buttonCallback() {
81901                 continueTo(rightClickHouse);
81902               }
81903             });
81904
81905             function continueTo(nextStep) {
81906               nextStep();
81907             }
81908           }
81909
81910           function doneSquare() {
81911             context.history().checkpoint('doneSquare');
81912             revealHouse(house, helpHtml('intro.buildings.done_square'), {
81913               buttonText: _t.html('intro.ok'),
81914               buttonCallback: function buttonCallback() {
81915                 continueTo(addTank);
81916               }
81917             });
81918
81919             function continueTo(nextStep) {
81920               nextStep();
81921             }
81922           }
81923
81924           function addTank() {
81925             context.enter(modeBrowse(context));
81926             context.history().reset('doneSquare');
81927             _tankID = null;
81928             var msec = transitionTime(tank, context.map().center());
81929
81930             if (msec) {
81931               reveal(null, null, {
81932                 duration: 0
81933               });
81934             }
81935
81936             context.map().centerZoomEase(tank, 19.5, msec);
81937             timeout(function () {
81938               reveal('button.add-area', helpHtml('intro.buildings.add_tank'));
81939               context.on('enter.intro', function (mode) {
81940                 if (mode.id !== 'add-area') return;
81941                 continueTo(startTank);
81942               });
81943             }, msec + 100);
81944
81945             function continueTo(nextStep) {
81946               context.on('enter.intro', null);
81947               nextStep();
81948             }
81949           }
81950
81951           function startTank() {
81952             if (context.mode().id !== 'add-area') {
81953               return continueTo(addTank);
81954             }
81955
81956             _tankID = null;
81957             timeout(function () {
81958               var startString = helpHtml('intro.buildings.start_tank') + helpHtml('intro.buildings.tank_edge_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap'));
81959               revealTank(tank, startString);
81960               context.map().on('move.intro drawn.intro', function () {
81961                 revealTank(tank, startString, {
81962                   duration: 0
81963                 });
81964               });
81965               context.on('enter.intro', function (mode) {
81966                 if (mode.id !== 'draw-area') return chapter.restart();
81967                 continueTo(continueTank);
81968               });
81969             }, 550); // after easing
81970
81971             function continueTo(nextStep) {
81972               context.map().on('move.intro drawn.intro', null);
81973               context.on('enter.intro', null);
81974               nextStep();
81975             }
81976           }
81977
81978           function continueTank() {
81979             if (context.mode().id !== 'draw-area') {
81980               return continueTo(addTank);
81981             }
81982
81983             _tankID = null;
81984             var continueString = helpHtml('intro.buildings.continue_tank') + '{br}' + helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.buildings.finish_tank');
81985             revealTank(tank, continueString);
81986             context.map().on('move.intro drawn.intro', function () {
81987               revealTank(tank, continueString, {
81988                 duration: 0
81989               });
81990             });
81991             context.on('enter.intro', function (mode) {
81992               if (mode.id === 'draw-area') {
81993                 return;
81994               } else if (mode.id === 'select') {
81995                 _tankID = context.selectedIDs()[0];
81996                 return continueTo(searchPresetTank);
81997               } else {
81998                 return continueTo(addTank);
81999               }
82000             });
82001
82002             function continueTo(nextStep) {
82003               context.map().on('move.intro drawn.intro', null);
82004               context.on('enter.intro', null);
82005               nextStep();
82006             }
82007           }
82008
82009           function searchPresetTank() {
82010             if (!_tankID || !context.hasEntity(_tankID)) {
82011               return addTank();
82012             }
82013
82014             var ids = context.selectedIDs();
82015
82016             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _tankID) {
82017               context.enter(modeSelect(context, [_tankID]));
82018             } // disallow scrolling
82019
82020
82021             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
82022             timeout(function () {
82023               // reset pane, in case user somehow happened to change it..
82024               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
82025               context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
82026               reveal('.preset-search-input', helpHtml('intro.buildings.search_tank', {
82027                 preset: tankPreset.name()
82028               }));
82029             }, 400); // after preset list pane visible..
82030
82031             context.on('enter.intro', function (mode) {
82032               if (!_tankID || !context.hasEntity(_tankID)) {
82033                 return continueTo(addTank);
82034               }
82035
82036               var ids = context.selectedIDs();
82037
82038               if (mode.id !== 'select' || !ids.length || ids[0] !== _tankID) {
82039                 // keep the user's area selected..
82040                 context.enter(modeSelect(context, [_tankID])); // reset pane, in case user somehow happened to change it..
82041
82042                 context.container().select('.inspector-wrap .panewrap').style('right', '-100%'); // disallow scrolling
82043
82044                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
82045                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
82046                 reveal('.preset-search-input', helpHtml('intro.buildings.search_tank', {
82047                   preset: tankPreset.name()
82048                 }));
82049                 context.history().on('change.intro', null);
82050               }
82051             });
82052
82053             function checkPresetSearch() {
82054               var first = context.container().select('.preset-list-item:first-child');
82055
82056               if (first.classed('preset-man_made-storage_tank')) {
82057                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.buildings.choose_tank', {
82058                   preset: tankPreset.name()
82059                 }), {
82060                   duration: 300
82061                 });
82062                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
82063                 context.history().on('change.intro', function () {
82064                   continueTo(closeEditorTank);
82065                 });
82066               }
82067             }
82068
82069             function continueTo(nextStep) {
82070               context.container().select('.inspector-wrap').on('wheel.intro', null);
82071               context.on('enter.intro', null);
82072               context.history().on('change.intro', null);
82073               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
82074               nextStep();
82075             }
82076           }
82077
82078           function closeEditorTank() {
82079             if (!_tankID || !context.hasEntity(_tankID)) {
82080               return addTank();
82081             }
82082
82083             var ids = context.selectedIDs();
82084
82085             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _tankID) {
82086               context.enter(modeSelect(context, [_tankID]));
82087             }
82088
82089             context.history().checkpoint('hasTank');
82090             context.on('exit.intro', function () {
82091               continueTo(rightClickTank);
82092             });
82093             timeout(function () {
82094               reveal('.entity-editor-pane', helpHtml('intro.buildings.close', {
82095                 button: icon('#iD-icon-close', 'inline')
82096               }));
82097             }, 500);
82098
82099             function continueTo(nextStep) {
82100               context.on('exit.intro', null);
82101               nextStep();
82102             }
82103           }
82104
82105           function rightClickTank() {
82106             if (!_tankID) return continueTo(addTank);
82107             context.enter(modeBrowse(context));
82108             context.history().reset('hasTank');
82109             context.map().centerEase(tank, 500);
82110             timeout(function () {
82111               context.on('enter.intro', function (mode) {
82112                 if (mode.id !== 'select') return;
82113                 var ids = context.selectedIDs();
82114                 if (ids.length !== 1 || ids[0] !== _tankID) return;
82115                 timeout(function () {
82116                   var node = selectMenuItem(context, 'circularize').node();
82117                   if (!node) return;
82118                   continueTo(clickCircle);
82119                 }, 50); // after menu visible
82120               });
82121               var rightclickString = helpHtml('intro.buildings.' + (context.lastPointerType() === 'mouse' ? 'rightclick_tank' : 'edit_menu_tank_touch'));
82122               revealTank(tank, rightclickString);
82123               context.map().on('move.intro drawn.intro', function () {
82124                 revealTank(tank, rightclickString, {
82125                   duration: 0
82126                 });
82127               });
82128               context.history().on('change.intro', function () {
82129                 continueTo(rightClickTank);
82130               });
82131             }, 600);
82132
82133             function continueTo(nextStep) {
82134               context.on('enter.intro', null);
82135               context.map().on('move.intro drawn.intro', null);
82136               context.history().on('change.intro', null);
82137               nextStep();
82138             }
82139           }
82140
82141           function clickCircle() {
82142             if (!_tankID) return chapter.restart();
82143             var entity = context.hasEntity(_tankID);
82144             if (!entity) return continueTo(rightClickTank);
82145             var node = selectMenuItem(context, 'circularize').node();
82146
82147             if (!node) {
82148               return continueTo(rightClickTank);
82149             }
82150
82151             var wasChanged = false;
82152             reveal('.edit-menu', helpHtml('intro.buildings.circle_tank'), {
82153               padding: 50
82154             });
82155             context.on('enter.intro', function (mode) {
82156               if (mode.id === 'browse') {
82157                 continueTo(rightClickTank);
82158               } else if (mode.id === 'move' || mode.id === 'rotate') {
82159                 continueTo(retryClickCircle);
82160               }
82161             });
82162             context.map().on('move.intro', function () {
82163               var node = selectMenuItem(context, 'circularize').node();
82164
82165               if (!wasChanged && !node) {
82166                 return continueTo(rightClickTank);
82167               }
82168
82169               reveal('.edit-menu', helpHtml('intro.buildings.circle_tank'), {
82170                 duration: 0,
82171                 padding: 50
82172               });
82173             });
82174             context.history().on('change.intro', function () {
82175               wasChanged = true;
82176               context.history().on('change.intro', null); // Something changed.  Wait for transition to complete and check undo annotation.
82177
82178               timeout(function () {
82179                 if (context.history().undoAnnotation() === _t('operations.circularize.annotation.feature', {
82180                   n: 1
82181                 })) {
82182                   continueTo(play);
82183                 } else {
82184                   continueTo(retryClickCircle);
82185                 }
82186               }, 500); // after transitioned actions
82187             });
82188
82189             function continueTo(nextStep) {
82190               context.on('enter.intro', null);
82191               context.map().on('move.intro', null);
82192               context.history().on('change.intro', null);
82193               nextStep();
82194             }
82195           }
82196
82197           function retryClickCircle() {
82198             context.enter(modeBrowse(context));
82199             revealTank(tank, helpHtml('intro.buildings.retry_circle'), {
82200               buttonText: _t.html('intro.ok'),
82201               buttonCallback: function buttonCallback() {
82202                 continueTo(rightClickTank);
82203               }
82204             });
82205
82206             function continueTo(nextStep) {
82207               nextStep();
82208             }
82209           }
82210
82211           function play() {
82212             dispatch$1.call('done');
82213             reveal('.ideditor', helpHtml('intro.buildings.play', {
82214               next: _t('intro.startediting.title')
82215             }), {
82216               tooltipBox: '.intro-nav-wrap .chapter-startEditing',
82217               buttonText: _t.html('intro.ok'),
82218               buttonCallback: function buttonCallback() {
82219                 reveal('.ideditor');
82220               }
82221             });
82222           }
82223
82224           chapter.enter = function () {
82225             addHouse();
82226           };
82227
82228           chapter.exit = function () {
82229             timeouts.forEach(window.clearTimeout);
82230             context.on('enter.intro exit.intro', null);
82231             context.map().on('move.intro drawn.intro', null);
82232             context.history().on('change.intro', null);
82233             context.container().select('.inspector-wrap').on('wheel.intro', null);
82234             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
82235             context.container().select('.more-fields .combobox-input').on('click.intro', null);
82236           };
82237
82238           chapter.restart = function () {
82239             chapter.exit();
82240             chapter.enter();
82241           };
82242
82243           return utilRebind(chapter, dispatch$1, 'on');
82244         }
82245
82246         function uiIntroStartEditing(context, reveal) {
82247           var dispatch$1 = dispatch('done', 'startEditing');
82248           var modalSelection = select(null);
82249           var chapter = {
82250             title: 'intro.startediting.title'
82251           };
82252
82253           function showHelp() {
82254             reveal('.map-control.help-control', helpHtml('intro.startediting.help'), {
82255               buttonText: _t.html('intro.ok'),
82256               buttonCallback: function buttonCallback() {
82257                 shortcuts();
82258               }
82259             });
82260           }
82261
82262           function shortcuts() {
82263             reveal('.map-control.help-control', helpHtml('intro.startediting.shortcuts'), {
82264               buttonText: _t.html('intro.ok'),
82265               buttonCallback: function buttonCallback() {
82266                 showSave();
82267               }
82268             });
82269           }
82270
82271           function showSave() {
82272             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
82273
82274             reveal('.top-toolbar button.save', helpHtml('intro.startediting.save'), {
82275               buttonText: _t.html('intro.ok'),
82276               buttonCallback: function buttonCallback() {
82277                 showStart();
82278               }
82279             });
82280           }
82281
82282           function showStart() {
82283             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
82284
82285             modalSelection = uiModal(context.container());
82286             modalSelection.select('.modal').attr('class', 'modal-splash modal');
82287             modalSelection.selectAll('.close').remove();
82288             var startbutton = modalSelection.select('.content').attr('class', 'fillL').append('button').attr('class', 'modal-section huge-modal-button').on('click', function () {
82289               modalSelection.remove();
82290             });
82291             startbutton.append('svg').attr('class', 'illustration').append('use').attr('xlink:href', '#iD-logo-walkthrough');
82292             startbutton.append('h2').html(_t.html('intro.startediting.start'));
82293             dispatch$1.call('startEditing');
82294           }
82295
82296           chapter.enter = function () {
82297             showHelp();
82298           };
82299
82300           chapter.exit = function () {
82301             modalSelection.remove();
82302             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
82303           };
82304
82305           return utilRebind(chapter, dispatch$1, 'on');
82306         }
82307
82308         var chapterUi = {
82309           welcome: uiIntroWelcome,
82310           navigation: uiIntroNavigation,
82311           point: uiIntroPoint,
82312           area: uiIntroArea,
82313           line: uiIntroLine,
82314           building: uiIntroBuilding,
82315           startEditing: uiIntroStartEditing
82316         };
82317         var chapterFlow = ['welcome', 'navigation', 'point', 'area', 'line', 'building', 'startEditing'];
82318         function uiIntro(context) {
82319           var INTRO_IMAGERY = 'EsriWorldImageryClarity';
82320           var _introGraph = {};
82321
82322           var _currChapter;
82323
82324           function intro(selection) {
82325             _mainFileFetcher.get('intro_graph').then(function (dataIntroGraph) {
82326               // create entities for intro graph and localize names
82327               for (var id in dataIntroGraph) {
82328                 if (!_introGraph[id]) {
82329                   _introGraph[id] = osmEntity(localize(dataIntroGraph[id]));
82330                 }
82331               }
82332
82333               selection.call(startIntro);
82334             })["catch"](function () {
82335               /* ignore */
82336             });
82337           }
82338
82339           function startIntro(selection) {
82340             context.enter(modeBrowse(context)); // Save current map state
82341
82342             var osm = context.connection();
82343             var history = context.history().toJSON();
82344             var hash = window.location.hash;
82345             var center = context.map().center();
82346             var zoom = context.map().zoom();
82347             var background = context.background().baseLayerSource();
82348             var overlays = context.background().overlayLayerSources();
82349             var opacity = context.container().selectAll('.main-map .layer-background').style('opacity');
82350             var caches = osm && osm.caches();
82351             var baseEntities = context.history().graph().base().entities; // Show sidebar and disable the sidebar resizing button
82352             // (this needs to be before `context.inIntro(true)`)
82353
82354             context.ui().sidebar.expand();
82355             context.container().selectAll('button.sidebar-toggle').classed('disabled', true); // Block saving
82356
82357             context.inIntro(true); // Load semi-real data used in intro
82358
82359             if (osm) {
82360               osm.toggle(false).reset();
82361             }
82362
82363             context.history().reset();
82364             context.history().merge(Object.values(coreGraph().load(_introGraph).entities));
82365             context.history().checkpoint('initial'); // Setup imagery
82366
82367             var imagery = context.background().findSource(INTRO_IMAGERY);
82368
82369             if (imagery) {
82370               context.background().baseLayerSource(imagery);
82371             } else {
82372               context.background().bing();
82373             }
82374
82375             overlays.forEach(function (d) {
82376               return context.background().toggleOverlayLayer(d);
82377             }); // Setup data layers (only OSM)
82378
82379             var layers = context.layers();
82380             layers.all().forEach(function (item) {
82381               // if the layer has the function `enabled`
82382               if (typeof item.layer.enabled === 'function') {
82383                 item.layer.enabled(item.id === 'osm');
82384               }
82385             });
82386             context.container().selectAll('.main-map .layer-background').style('opacity', 1);
82387             var curtain = uiCurtain(context.container().node());
82388             selection.call(curtain); // Store that the user started the walkthrough..
82389
82390             corePreferences('walkthrough_started', 'yes'); // Restore previous walkthrough progress..
82391
82392             var storedProgress = corePreferences('walkthrough_progress') || '';
82393             var progress = storedProgress.split(';').filter(Boolean);
82394             var chapters = chapterFlow.map(function (chapter, i) {
82395               var s = chapterUi[chapter](context, curtain.reveal).on('done', function () {
82396                 buttons.filter(function (d) {
82397                   return d.title === s.title;
82398                 }).classed('finished', true);
82399
82400                 if (i < chapterFlow.length - 1) {
82401                   var next = chapterFlow[i + 1];
82402                   context.container().select("button.chapter-".concat(next)).classed('next', true);
82403                 } // Store walkthrough progress..
82404
82405
82406                 progress.push(chapter);
82407                 corePreferences('walkthrough_progress', utilArrayUniq(progress).join(';'));
82408               });
82409               return s;
82410             });
82411             chapters[chapters.length - 1].on('startEditing', function () {
82412               // Store walkthrough progress..
82413               progress.push('startEditing');
82414               corePreferences('walkthrough_progress', utilArrayUniq(progress).join(';')); // Store if walkthrough is completed..
82415
82416               var incomplete = utilArrayDifference(chapterFlow, progress);
82417
82418               if (!incomplete.length) {
82419                 corePreferences('walkthrough_completed', 'yes');
82420               }
82421
82422               curtain.remove();
82423               navwrap.remove();
82424               context.container().selectAll('.main-map .layer-background').style('opacity', opacity);
82425               context.container().selectAll('button.sidebar-toggle').classed('disabled', false);
82426
82427               if (osm) {
82428                 osm.toggle(true).reset().caches(caches);
82429               }
82430
82431               context.history().reset().merge(Object.values(baseEntities));
82432               context.background().baseLayerSource(background);
82433               overlays.forEach(function (d) {
82434                 return context.background().toggleOverlayLayer(d);
82435               });
82436
82437               if (history) {
82438                 context.history().fromJSON(history, false);
82439               }
82440
82441               context.map().centerZoom(center, zoom);
82442               window.location.replace(hash);
82443               context.inIntro(false);
82444             });
82445             var navwrap = selection.append('div').attr('class', 'intro-nav-wrap fillD');
82446             navwrap.append('svg').attr('class', 'intro-nav-wrap-logo').append('use').attr('xlink:href', '#iD-logo-walkthrough');
82447             var buttonwrap = navwrap.append('div').attr('class', 'joined').selectAll('button.chapter');
82448             var buttons = buttonwrap.data(chapters).enter().append('button').attr('class', function (d, i) {
82449               return "chapter chapter-".concat(chapterFlow[i]);
82450             }).on('click', enterChapter);
82451             buttons.append('span').html(function (d) {
82452               return _t.html(d.title);
82453             });
82454             buttons.append('span').attr('class', 'status').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward', 'inline'));
82455             enterChapter(null, chapters[0]);
82456
82457             function enterChapter(d3_event, newChapter) {
82458               if (_currChapter) {
82459                 _currChapter.exit();
82460               }
82461
82462               context.enter(modeBrowse(context));
82463               _currChapter = newChapter;
82464
82465               _currChapter.enter();
82466
82467               buttons.classed('next', false).classed('active', function (d) {
82468                 return d.title === _currChapter.title;
82469               });
82470             }
82471           }
82472
82473           return intro;
82474         }
82475
82476         function uiIssuesInfo(context) {
82477           var warningsItem = {
82478             id: 'warnings',
82479             count: 0,
82480             iconID: 'iD-icon-alert',
82481             descriptionID: 'issues.warnings_and_errors'
82482           };
82483           var resolvedItem = {
82484             id: 'resolved',
82485             count: 0,
82486             iconID: 'iD-icon-apply',
82487             descriptionID: 'issues.user_resolved_issues'
82488           };
82489
82490           function update(selection) {
82491             var shownItems = [];
82492             var liveIssues = context.validator().getIssues({
82493               what: corePreferences('validate-what') || 'edited',
82494               where: corePreferences('validate-where') || 'all'
82495             });
82496
82497             if (liveIssues.length) {
82498               warningsItem.count = liveIssues.length;
82499               shownItems.push(warningsItem);
82500             }
82501
82502             if (corePreferences('validate-what') === 'all') {
82503               var resolvedIssues = context.validator().getResolvedIssues();
82504
82505               if (resolvedIssues.length) {
82506                 resolvedItem.count = resolvedIssues.length;
82507                 shownItems.push(resolvedItem);
82508               }
82509             }
82510
82511             var chips = selection.selectAll('.chip').data(shownItems, function (d) {
82512               return d.id;
82513             });
82514             chips.exit().remove();
82515             var enter = chips.enter().append('a').attr('class', function (d) {
82516               return 'chip ' + d.id + '-count';
82517             }).attr('href', '#').each(function (d) {
82518               var chipSelection = select(this);
82519               var tooltipBehavior = uiTooltip().placement('top').title(_t.html(d.descriptionID));
82520               chipSelection.call(tooltipBehavior).on('click', function (d3_event) {
82521                 d3_event.preventDefault();
82522                 tooltipBehavior.hide(select(this)); // open the Issues pane
82523
82524                 context.ui().togglePanes(context.container().select('.map-panes .issues-pane'));
82525               });
82526               chipSelection.call(svgIcon('#' + d.iconID));
82527             });
82528             enter.append('span').attr('class', 'count');
82529             enter.merge(chips).selectAll('span.count').html(function (d) {
82530               return d.count.toString();
82531             });
82532           }
82533
82534           return function (selection) {
82535             update(selection);
82536             context.validator().on('validated.infobox', function () {
82537               update(selection);
82538             });
82539           };
82540         }
82541
82542         function uiMapInMap(context) {
82543           function mapInMap(selection) {
82544             var backgroundLayer = rendererTileLayer(context);
82545             var overlayLayers = {};
82546             var projection = geoRawMercator();
82547             var dataLayer = svgData(projection, context).showLabels(false);
82548             var debugLayer = svgDebug(projection, context);
82549             var zoom = d3_zoom().scaleExtent([geoZoomToScale(0.5), geoZoomToScale(24)]).on('start', zoomStarted).on('zoom', zoomed).on('end', zoomEnded);
82550             var wrap = select(null);
82551             var tiles = select(null);
82552             var viewport = select(null);
82553             var _isTransformed = false;
82554             var _isHidden = true;
82555             var _skipEvents = false;
82556             var _gesture = null;
82557             var _zDiff = 6; // by default, minimap renders at (main zoom - 6)
82558
82559             var _dMini; // dimensions of minimap
82560
82561
82562             var _cMini; // center pixel of minimap
82563
82564
82565             var _tStart; // transform at start of gesture
82566
82567
82568             var _tCurr; // transform at most recent event
82569
82570
82571             var _timeoutID;
82572
82573             function zoomStarted() {
82574               if (_skipEvents) return;
82575               _tStart = _tCurr = projection.transform();
82576               _gesture = null;
82577             }
82578
82579             function zoomed(d3_event) {
82580               if (_skipEvents) return;
82581               var x = d3_event.transform.x;
82582               var y = d3_event.transform.y;
82583               var k = d3_event.transform.k;
82584               var isZooming = k !== _tStart.k;
82585               var isPanning = x !== _tStart.x || y !== _tStart.y;
82586
82587               if (!isZooming && !isPanning) {
82588                 return; // no change
82589               } // lock in either zooming or panning, don't allow both in minimap.
82590
82591
82592               if (!_gesture) {
82593                 _gesture = isZooming ? 'zoom' : 'pan';
82594               }
82595
82596               var tMini = projection.transform();
82597               var tX, tY, scale;
82598
82599               if (_gesture === 'zoom') {
82600                 scale = k / tMini.k;
82601                 tX = (_cMini[0] / scale - _cMini[0]) * scale;
82602                 tY = (_cMini[1] / scale - _cMini[1]) * scale;
82603               } else {
82604                 k = tMini.k;
82605                 scale = 1;
82606                 tX = x - tMini.x;
82607                 tY = y - tMini.y;
82608               }
82609
82610               utilSetTransform(tiles, tX, tY, scale);
82611               utilSetTransform(viewport, 0, 0, scale);
82612               _isTransformed = true;
82613               _tCurr = identity$2.translate(x, y).scale(k);
82614               var zMain = geoScaleToZoom(context.projection.scale());
82615               var zMini = geoScaleToZoom(k);
82616               _zDiff = zMain - zMini;
82617               queueRedraw();
82618             }
82619
82620             function zoomEnded() {
82621               if (_skipEvents) return;
82622               if (_gesture !== 'pan') return;
82623               updateProjection();
82624               _gesture = null;
82625               context.map().center(projection.invert(_cMini)); // recenter main map..
82626             }
82627
82628             function updateProjection() {
82629               var loc = context.map().center();
82630               var tMain = context.projection.transform();
82631               var zMain = geoScaleToZoom(tMain.k);
82632               var zMini = Math.max(zMain - _zDiff, 0.5);
82633               var kMini = geoZoomToScale(zMini);
82634               projection.translate([tMain.x, tMain.y]).scale(kMini);
82635               var point = projection(loc);
82636               var mouse = _gesture === 'pan' ? geoVecSubtract([_tCurr.x, _tCurr.y], [_tStart.x, _tStart.y]) : [0, 0];
82637               var xMini = _cMini[0] - point[0] + tMain.x + mouse[0];
82638               var yMini = _cMini[1] - point[1] + tMain.y + mouse[1];
82639               projection.translate([xMini, yMini]).clipExtent([[0, 0], _dMini]);
82640               _tCurr = projection.transform();
82641
82642               if (_isTransformed) {
82643                 utilSetTransform(tiles, 0, 0);
82644                 utilSetTransform(viewport, 0, 0);
82645                 _isTransformed = false;
82646               }
82647
82648               zoom.scaleExtent([geoZoomToScale(0.5), geoZoomToScale(zMain - 3)]);
82649               _skipEvents = true;
82650               wrap.call(zoom.transform, _tCurr);
82651               _skipEvents = false;
82652             }
82653
82654             function redraw() {
82655               clearTimeout(_timeoutID);
82656               if (_isHidden) return;
82657               updateProjection();
82658               var zMini = geoScaleToZoom(projection.scale()); // setup tile container
82659
82660               tiles = wrap.selectAll('.map-in-map-tiles').data([0]);
82661               tiles = tiles.enter().append('div').attr('class', 'map-in-map-tiles').merge(tiles); // redraw background
82662
82663               backgroundLayer.source(context.background().baseLayerSource()).projection(projection).dimensions(_dMini);
82664               var background = tiles.selectAll('.map-in-map-background').data([0]);
82665               background.enter().append('div').attr('class', 'map-in-map-background').merge(background).call(backgroundLayer); // redraw overlay
82666
82667               var overlaySources = context.background().overlayLayerSources();
82668               var activeOverlayLayers = [];
82669
82670               for (var i = 0; i < overlaySources.length; i++) {
82671                 if (overlaySources[i].validZoom(zMini)) {
82672                   if (!overlayLayers[i]) overlayLayers[i] = rendererTileLayer(context);
82673                   activeOverlayLayers.push(overlayLayers[i].source(overlaySources[i]).projection(projection).dimensions(_dMini));
82674                 }
82675               }
82676
82677               var overlay = tiles.selectAll('.map-in-map-overlay').data([0]);
82678               overlay = overlay.enter().append('div').attr('class', 'map-in-map-overlay').merge(overlay);
82679               var overlays = overlay.selectAll('div').data(activeOverlayLayers, function (d) {
82680                 return d.source().name();
82681               });
82682               overlays.exit().remove();
82683               overlays = overlays.enter().append('div').merge(overlays).each(function (layer) {
82684                 select(this).call(layer);
82685               });
82686               var dataLayers = tiles.selectAll('.map-in-map-data').data([0]);
82687               dataLayers.exit().remove();
82688               dataLayers = dataLayers.enter().append('svg').attr('class', 'map-in-map-data').merge(dataLayers).call(dataLayer).call(debugLayer); // redraw viewport bounding box
82689
82690               if (_gesture !== 'pan') {
82691                 var getPath = d3_geoPath(projection);
82692                 var bbox = {
82693                   type: 'Polygon',
82694                   coordinates: [context.map().extent().polygon()]
82695                 };
82696                 viewport = wrap.selectAll('.map-in-map-viewport').data([0]);
82697                 viewport = viewport.enter().append('svg').attr('class', 'map-in-map-viewport').merge(viewport);
82698                 var path = viewport.selectAll('.map-in-map-bbox').data([bbox]);
82699                 path.enter().append('path').attr('class', 'map-in-map-bbox').merge(path).attr('d', getPath).classed('thick', function (d) {
82700                   return getPath.area(d) < 30;
82701                 });
82702               }
82703             }
82704
82705             function queueRedraw() {
82706               clearTimeout(_timeoutID);
82707               _timeoutID = setTimeout(function () {
82708                 redraw();
82709               }, 750);
82710             }
82711
82712             function toggle(d3_event) {
82713               if (d3_event) d3_event.preventDefault();
82714               _isHidden = !_isHidden;
82715               context.container().select('.minimap-toggle-item').classed('active', !_isHidden).select('input').property('checked', !_isHidden);
82716
82717               if (_isHidden) {
82718                 wrap.style('display', 'block').style('opacity', '1').transition().duration(200).style('opacity', '0').on('end', function () {
82719                   selection.selectAll('.map-in-map').style('display', 'none');
82720                 });
82721               } else {
82722                 wrap.style('display', 'block').style('opacity', '0').transition().duration(200).style('opacity', '1').on('end', function () {
82723                   redraw();
82724                 });
82725               }
82726             }
82727
82728             uiMapInMap.toggle = toggle;
82729             wrap = selection.selectAll('.map-in-map').data([0]);
82730             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..
82731
82732             _dMini = [200, 150]; //utilGetDimensions(wrap);
82733
82734             _cMini = geoVecScale(_dMini, 0.5);
82735             context.map().on('drawn.map-in-map', function (drawn) {
82736               if (drawn.full === true) {
82737                 redraw();
82738               }
82739             });
82740             redraw();
82741             context.keybinding().on(_t('background.minimap.key'), toggle);
82742           }
82743
82744           return mapInMap;
82745         }
82746
82747         function uiNotice(context) {
82748           return function (selection) {
82749             var div = selection.append('div').attr('class', 'notice');
82750             var button = div.append('button').attr('class', 'zoom-to notice fillD').on('click', function () {
82751               context.map().zoomEase(context.minEditableZoom());
82752             }).on('wheel', function (d3_event) {
82753               // let wheel events pass through #4482
82754               var e2 = new WheelEvent(d3_event.type, d3_event);
82755               context.surface().node().dispatchEvent(e2);
82756             });
82757             button.call(svgIcon('#iD-icon-plus', 'pre-text')).append('span').attr('class', 'label').html(_t.html('zoom_in_edit'));
82758
82759             function disableTooHigh() {
82760               var canEdit = context.map().zoom() >= context.minEditableZoom();
82761               div.style('display', canEdit ? 'none' : 'block');
82762             }
82763
82764             context.map().on('move.notice', debounce(disableTooHigh, 500));
82765             disableTooHigh();
82766           };
82767         }
82768
82769         function uiPhotoviewer(context) {
82770           var dispatch$1 = dispatch('resize');
82771
82772           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
82773
82774           function photoviewer(selection) {
82775             selection.append('button').attr('class', 'thumb-hide').on('click', function () {
82776               if (services.streetside) {
82777                 services.streetside.hideViewer(context);
82778               }
82779
82780               if (services.mapillary) {
82781                 services.mapillary.hideViewer(context);
82782               }
82783
82784               if (services.openstreetcam) {
82785                 services.openstreetcam.hideViewer(context);
82786               }
82787             }).append('div').call(svgIcon('#iD-icon-close'));
82788
82789             function preventDefault(d3_event) {
82790               d3_event.preventDefault();
82791             }
82792
82793             selection.append('button').attr('class', 'resize-handle-xy').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch$1, {
82794               resizeOnX: true,
82795               resizeOnY: true
82796             }));
82797             selection.append('button').attr('class', 'resize-handle-x').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch$1, {
82798               resizeOnX: true
82799             }));
82800             selection.append('button').attr('class', 'resize-handle-y').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch$1, {
82801               resizeOnY: true
82802             }));
82803
82804             function buildResizeListener(target, eventName, dispatch, options) {
82805               var resizeOnX = !!options.resizeOnX;
82806               var resizeOnY = !!options.resizeOnY;
82807               var minHeight = options.minHeight || 240;
82808               var minWidth = options.minWidth || 320;
82809               var pointerId;
82810               var startX;
82811               var startY;
82812               var startWidth;
82813               var startHeight;
82814
82815               function startResize(d3_event) {
82816                 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
82817                 d3_event.preventDefault();
82818                 d3_event.stopPropagation();
82819                 var mapSize = context.map().dimensions();
82820
82821                 if (resizeOnX) {
82822                   var maxWidth = mapSize[0];
82823                   var newWidth = clamp(startWidth + d3_event.clientX - startX, minWidth, maxWidth);
82824                   target.style('width', newWidth + 'px');
82825                 }
82826
82827                 if (resizeOnY) {
82828                   var maxHeight = mapSize[1] - 90; // preserve space at top/bottom of map
82829
82830                   var newHeight = clamp(startHeight + startY - d3_event.clientY, minHeight, maxHeight);
82831                   target.style('height', newHeight + 'px');
82832                 }
82833
82834                 dispatch.call(eventName, target, utilGetDimensions(target, true));
82835               }
82836
82837               function clamp(num, min, max) {
82838                 return Math.max(min, Math.min(num, max));
82839               }
82840
82841               function stopResize(d3_event) {
82842                 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
82843                 d3_event.preventDefault();
82844                 d3_event.stopPropagation(); // remove all the listeners we added
82845
82846                 select(window).on('.' + eventName, null);
82847               }
82848
82849               return function initResize(d3_event) {
82850                 d3_event.preventDefault();
82851                 d3_event.stopPropagation();
82852                 pointerId = d3_event.pointerId || 'mouse';
82853                 startX = d3_event.clientX;
82854                 startY = d3_event.clientY;
82855                 var targetRect = target.node().getBoundingClientRect();
82856                 startWidth = targetRect.width;
82857                 startHeight = targetRect.height;
82858                 select(window).on(_pointerPrefix + 'move.' + eventName, startResize, false).on(_pointerPrefix + 'up.' + eventName, stopResize, false);
82859
82860                 if (_pointerPrefix === 'pointer') {
82861                   select(window).on('pointercancel.' + eventName, stopResize, false);
82862                 }
82863               };
82864             }
82865           }
82866
82867           photoviewer.onMapResize = function () {
82868             var photoviewer = context.container().select('.photoviewer');
82869             var content = context.container().select('.main-content');
82870             var mapDimensions = utilGetDimensions(content, true); // shrink photo viewer if it is too big
82871             // (-90 preserves space at top and bottom of map used by menus)
82872
82873             var photoDimensions = utilGetDimensions(photoviewer, true);
82874
82875             if (photoDimensions[0] > mapDimensions[0] || photoDimensions[1] > mapDimensions[1] - 90) {
82876               var setPhotoDimensions = [Math.min(photoDimensions[0], mapDimensions[0]), Math.min(photoDimensions[1], mapDimensions[1] - 90)];
82877               photoviewer.style('width', setPhotoDimensions[0] + 'px').style('height', setPhotoDimensions[1] + 'px');
82878               dispatch$1.call('resize', photoviewer, setPhotoDimensions);
82879             }
82880           };
82881
82882           return utilRebind(photoviewer, dispatch$1, 'on');
82883         }
82884
82885         function uiRestore(context) {
82886           return function (selection) {
82887             if (!context.history().hasRestorableChanges()) return;
82888             var modalSelection = uiModal(selection, true);
82889             modalSelection.select('.modal').attr('class', 'modal fillL');
82890             var introModal = modalSelection.select('.content');
82891             introModal.append('div').attr('class', 'modal-section').append('h3').html(_t.html('restore.heading'));
82892             introModal.append('div').attr('class', 'modal-section').append('p').html(_t.html('restore.description'));
82893             var buttonWrap = introModal.append('div').attr('class', 'modal-actions');
82894             var restore = buttonWrap.append('button').attr('class', 'restore').on('click', function () {
82895               context.history().restore();
82896               modalSelection.remove();
82897             });
82898             restore.append('svg').attr('class', 'logo logo-restore').append('use').attr('xlink:href', '#iD-logo-restore');
82899             restore.append('div').html(_t.html('restore.restore'));
82900             var reset = buttonWrap.append('button').attr('class', 'reset').on('click', function () {
82901               context.history().clearSaved();
82902               modalSelection.remove();
82903             });
82904             reset.append('svg').attr('class', 'logo logo-reset').append('use').attr('xlink:href', '#iD-logo-reset');
82905             reset.append('div').html(_t.html('restore.reset'));
82906             restore.node().focus();
82907           };
82908         }
82909
82910         function uiScale(context) {
82911           var projection = context.projection,
82912               isImperial = !_mainLocalizer.usesMetric(),
82913               maxLength = 180,
82914               tickHeight = 8;
82915
82916           function scaleDefs(loc1, loc2) {
82917             var lat = (loc2[1] + loc1[1]) / 2,
82918                 conversion = isImperial ? 3.28084 : 1,
82919                 dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion,
82920                 scale = {
82921               dist: 0,
82922               px: 0,
82923               text: ''
82924             },
82925                 buckets,
82926                 i,
82927                 val,
82928                 dLon;
82929
82930             if (isImperial) {
82931               buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
82932             } else {
82933               buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
82934             } // determine a user-friendly endpoint for the scale
82935
82936
82937             for (i = 0; i < buckets.length; i++) {
82938               val = buckets[i];
82939
82940               if (dist >= val) {
82941                 scale.dist = Math.floor(dist / val) * val;
82942                 break;
82943               } else {
82944                 scale.dist = +dist.toFixed(2);
82945               }
82946             }
82947
82948             dLon = geoMetersToLon(scale.dist / conversion, lat);
82949             scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
82950             scale.text = displayLength(scale.dist / conversion, isImperial);
82951             return scale;
82952           }
82953
82954           function update(selection) {
82955             // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
82956             var dims = context.map().dimensions(),
82957                 loc1 = projection.invert([0, dims[1]]),
82958                 loc2 = projection.invert([maxLength, dims[1]]),
82959                 scale = scaleDefs(loc1, loc2);
82960             selection.select('.scale-path').attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
82961             selection.select('.scale-text').style(_mainLocalizer.textDirection() === 'ltr' ? 'left' : 'right', scale.px + 16 + 'px').html(scale.text);
82962           }
82963
82964           return function (selection) {
82965             function switchUnits() {
82966               isImperial = !isImperial;
82967               selection.call(update);
82968             }
82969
82970             var scalegroup = selection.append('svg').attr('class', 'scale').on('click', switchUnits).append('g').attr('transform', 'translate(10,11)');
82971             scalegroup.append('path').attr('class', 'scale-path');
82972             selection.append('div').attr('class', 'scale-text');
82973             selection.call(update);
82974             context.map().on('move.scale', function () {
82975               update(selection);
82976             });
82977           };
82978         }
82979
82980         function uiShortcuts(context) {
82981           var detected = utilDetect();
82982           var _activeTab = 0;
82983
82984           var _modalSelection;
82985
82986           var _selection = select(null);
82987
82988           var _dataShortcuts;
82989
82990           function shortcutsModal(_modalSelection) {
82991             _modalSelection.select('.modal').classed('modal-shortcuts', true);
82992
82993             var content = _modalSelection.select('.content');
82994
82995             content.append('div').attr('class', 'modal-section').append('h3').html(_t.html('shortcuts.title'));
82996             _mainFileFetcher.get('shortcuts').then(function (data) {
82997               _dataShortcuts = data;
82998               content.call(render);
82999             })["catch"](function () {
83000               /* ignore */
83001             });
83002           }
83003
83004           function render(selection) {
83005             if (!_dataShortcuts) return;
83006             var wrapper = selection.selectAll('.wrapper').data([0]);
83007             var wrapperEnter = wrapper.enter().append('div').attr('class', 'wrapper modal-section');
83008             var tabsBar = wrapperEnter.append('div').attr('class', 'tabs-bar');
83009             var shortcutsList = wrapperEnter.append('div').attr('class', 'shortcuts-list');
83010             wrapper = wrapper.merge(wrapperEnter);
83011             var tabs = tabsBar.selectAll('.tab').data(_dataShortcuts);
83012             var tabsEnter = tabs.enter().append('a').attr('class', 'tab').attr('href', '#').on('click', function (d3_event, d) {
83013               d3_event.preventDefault();
83014
83015               var i = _dataShortcuts.indexOf(d);
83016
83017               _activeTab = i;
83018               render(selection);
83019             });
83020             tabsEnter.append('span').html(function (d) {
83021               return _t.html(d.text);
83022             }); // Update
83023
83024             wrapper.selectAll('.tab').classed('active', function (d, i) {
83025               return i === _activeTab;
83026             });
83027             var shortcuts = shortcutsList.selectAll('.shortcut-tab').data(_dataShortcuts);
83028             var shortcutsEnter = shortcuts.enter().append('div').attr('class', function (d) {
83029               return 'shortcut-tab shortcut-tab-' + d.tab;
83030             });
83031             var columnsEnter = shortcutsEnter.selectAll('.shortcut-column').data(function (d) {
83032               return d.columns;
83033             }).enter().append('table').attr('class', 'shortcut-column');
83034             var rowsEnter = columnsEnter.selectAll('.shortcut-row').data(function (d) {
83035               return d.rows;
83036             }).enter().append('tr').attr('class', 'shortcut-row');
83037             var sectionRows = rowsEnter.filter(function (d) {
83038               return !d.shortcuts;
83039             });
83040             sectionRows.append('td');
83041             sectionRows.append('td').attr('class', 'shortcut-section').append('h3').html(function (d) {
83042               return _t.html(d.text);
83043             });
83044             var shortcutRows = rowsEnter.filter(function (d) {
83045               return d.shortcuts;
83046             });
83047             var shortcutKeys = shortcutRows.append('td').attr('class', 'shortcut-keys');
83048             var modifierKeys = shortcutKeys.filter(function (d) {
83049               return d.modifiers;
83050             });
83051             modifierKeys.selectAll('kbd.modifier').data(function (d) {
83052               if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
83053                 return ['⌘'];
83054               } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
83055                 return [];
83056               } else {
83057                 return d.modifiers;
83058               }
83059             }).enter().each(function () {
83060               var selection = select(this);
83061               selection.append('kbd').attr('class', 'modifier').html(function (d) {
83062                 return uiCmd.display(d);
83063               });
83064               selection.append('span').html('+');
83065             });
83066             shortcutKeys.selectAll('kbd.shortcut').data(function (d) {
83067               var arr = d.shortcuts;
83068
83069               if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
83070                 arr = ['Y'];
83071               } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
83072                 arr = ['F11'];
83073               } // replace translations
83074
83075
83076               arr = arr.map(function (s) {
83077                 return uiCmd.display(s.indexOf('.') !== -1 ? _t(s) : s);
83078               });
83079               return utilArrayUniq(arr).map(function (s) {
83080                 return {
83081                   shortcut: s,
83082                   separator: d.separator,
83083                   suffix: d.suffix
83084                 };
83085               });
83086             }).enter().each(function (d, i, nodes) {
83087               var selection = select(this);
83088               var click = d.shortcut.toLowerCase().match(/(.*).click/);
83089
83090               if (click && click[1]) {
83091                 // replace "left_click", "right_click" with mouse icon
83092                 selection.call(svgIcon('#iD-walkthrough-mouse-' + click[1], 'operation'));
83093               } else if (d.shortcut.toLowerCase() === 'long-press') {
83094                 selection.call(svgIcon('#iD-walkthrough-longpress', 'longpress operation'));
83095               } else if (d.shortcut.toLowerCase() === 'tap') {
83096                 selection.call(svgIcon('#iD-walkthrough-tap', 'tap operation'));
83097               } else {
83098                 selection.append('kbd').attr('class', 'shortcut').html(function (d) {
83099                   return d.shortcut;
83100                 });
83101               }
83102
83103               if (i < nodes.length - 1) {
83104                 selection.append('span').html(d.separator || "\xA0" + _t.html('shortcuts.or') + "\xA0");
83105               } else if (i === nodes.length - 1 && d.suffix) {
83106                 selection.append('span').html(d.suffix);
83107               }
83108             });
83109             shortcutKeys.filter(function (d) {
83110               return d.gesture;
83111             }).each(function () {
83112               var selection = select(this);
83113               selection.append('span').html('+');
83114               selection.append('span').attr('class', 'gesture').html(function (d) {
83115                 return _t.html(d.gesture);
83116               });
83117             });
83118             shortcutRows.append('td').attr('class', 'shortcut-desc').html(function (d) {
83119               return d.text ? _t.html(d.text) : "\xA0";
83120             }); // Update
83121
83122             wrapper.selectAll('.shortcut-tab').style('display', function (d, i) {
83123               return i === _activeTab ? 'flex' : 'none';
83124             });
83125           }
83126
83127           return function (selection, show) {
83128             _selection = selection;
83129
83130             if (show) {
83131               _modalSelection = uiModal(selection);
83132
83133               _modalSelection.call(shortcutsModal);
83134             } else {
83135               context.keybinding().on([_t('shortcuts.toggle.key'), '?'], function () {
83136                 if (context.container().selectAll('.modal-shortcuts').size()) {
83137                   // already showing
83138                   if (_modalSelection) {
83139                     _modalSelection.close();
83140
83141                     _modalSelection = null;
83142                   }
83143                 } else {
83144                   _modalSelection = uiModal(_selection);
83145
83146                   _modalSelection.call(shortcutsModal);
83147                 }
83148               });
83149             }
83150           };
83151         }
83152
83153         var pair_1 = pair;
83154
83155         function search(input, dims) {
83156           if (!dims) dims = 'NSEW';
83157           if (typeof input !== 'string') return null;
83158           input = input.toUpperCase();
83159           var regex = /^[\s\,]*([NSEW])?\s*([\-|\—|\―]?[0-9.]+)[°º˚]?\s*(?:([0-9.]+)['’′‘]\s*)?(?:([0-9.]+)(?:''|"|”|″)\s*)?([NSEW])?/;
83160           var m = input.match(regex);
83161           if (!m) return null; // no match
83162
83163           var matched = m[0]; // extract dimension.. m[1] = leading, m[5] = trailing
83164
83165           var dim;
83166
83167           if (m[1] && m[5]) {
83168             // if matched both..
83169             dim = m[1]; // keep leading
83170
83171             matched = matched.slice(0, -1); // remove trailing dimension from match
83172           } else {
83173             dim = m[1] || m[5];
83174           } // if unrecognized dimension
83175
83176
83177           if (dim && dims.indexOf(dim) === -1) return null; // extract DMS
83178
83179           var deg = m[2] ? parseFloat(m[2]) : 0;
83180           var min = m[3] ? parseFloat(m[3]) / 60 : 0;
83181           var sec = m[4] ? parseFloat(m[4]) / 3600 : 0;
83182           var sign = deg < 0 ? -1 : 1;
83183           if (dim === 'S' || dim === 'W') sign *= -1;
83184           return {
83185             val: (Math.abs(deg) + min + sec) * sign,
83186             dim: dim,
83187             matched: matched,
83188             remain: input.slice(matched.length)
83189           };
83190         }
83191
83192         function pair(input, dims) {
83193           input = input.trim();
83194           var one = search(input, dims);
83195           if (!one) return null;
83196           input = one.remain.trim();
83197           var two = search(input, dims);
83198           if (!two || two.remain) return null;
83199
83200           if (one.dim) {
83201             return swapdim(one.val, two.val, one.dim);
83202           } else {
83203             return [one.val, two.val];
83204           }
83205         }
83206
83207         function swapdim(a, b, dim) {
83208           if (dim === 'N' || dim === 'S') return [a, b];
83209           if (dim === 'W' || dim === 'E') return [b, a];
83210         }
83211
83212         function uiFeatureList(context) {
83213           var _geocodeResults;
83214
83215           function featureList(selection) {
83216             var header = selection.append('div').attr('class', 'header fillL');
83217             header.append('h3').html(_t.html('inspector.feature_list'));
83218             var searchWrap = selection.append('div').attr('class', 'search-header');
83219             searchWrap.call(svgIcon('#iD-icon-search', 'pre-text'));
83220             var search = searchWrap.append('input').attr('placeholder', _t('inspector.search')).attr('type', 'search').call(utilNoAuto).on('keypress', keypress).on('keydown', keydown).on('input', inputevent);
83221             var listWrap = selection.append('div').attr('class', 'inspector-body');
83222             var list = listWrap.append('div').attr('class', 'feature-list');
83223             context.on('exit.feature-list', clearSearch);
83224             context.map().on('drawn.feature-list', mapDrawn);
83225             context.keybinding().on(uiCmd('⌘F'), focusSearch);
83226
83227             function focusSearch(d3_event) {
83228               var mode = context.mode() && context.mode().id;
83229               if (mode !== 'browse') return;
83230               d3_event.preventDefault();
83231               search.node().focus();
83232             }
83233
83234             function keydown(d3_event) {
83235               if (d3_event.keyCode === 27) {
83236                 // escape
83237                 search.node().blur();
83238               }
83239             }
83240
83241             function keypress(d3_event) {
83242               var q = search.property('value'),
83243                   items = list.selectAll('.feature-list-item');
83244
83245               if (d3_event.keyCode === 13 && // ↩ Return
83246               q.length && items.size()) {
83247                 click(items.datum());
83248               }
83249             }
83250
83251             function inputevent() {
83252               _geocodeResults = undefined;
83253               drawList();
83254             }
83255
83256             function clearSearch() {
83257               search.property('value', '');
83258               drawList();
83259             }
83260
83261             function mapDrawn(e) {
83262               if (e.full) {
83263                 drawList();
83264               }
83265             }
83266
83267             function features() {
83268               var result = [];
83269               var graph = context.graph();
83270               var visibleCenter = context.map().extent().center();
83271               var q = search.property('value').toLowerCase();
83272               if (!q) return result;
83273               var locationMatch = pair_1(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
83274
83275               if (locationMatch) {
83276                 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
83277                 result.push({
83278                   id: -1,
83279                   geometry: 'point',
83280                   type: _t('inspector.location'),
83281                   name: dmsCoordinatePair([loc[1], loc[0]]),
83282                   location: loc
83283                 });
83284               } // A location search takes priority over an ID search
83285
83286
83287               var idMatch = !locationMatch && q.match(/(?:^|\W)(node|way|relation|[nwr])\W?0*([1-9]\d*)(?:\W|$)/i);
83288
83289               if (idMatch) {
83290                 var elemType = idMatch[1].charAt(0);
83291                 var elemId = idMatch[2];
83292                 result.push({
83293                   id: elemType + elemId,
83294                   geometry: elemType === 'n' ? 'point' : elemType === 'w' ? 'line' : 'relation',
83295                   type: elemType === 'n' ? _t('inspector.node') : elemType === 'w' ? _t('inspector.way') : _t('inspector.relation'),
83296                   name: elemId
83297                 });
83298               }
83299
83300               var allEntities = graph.entities;
83301               var localResults = [];
83302
83303               for (var id in allEntities) {
83304                 var entity = allEntities[id];
83305                 if (!entity) continue;
83306                 var name = utilDisplayName(entity) || '';
83307                 if (name.toLowerCase().indexOf(q) < 0) continue;
83308                 var matched = _mainPresetIndex.match(entity, graph);
83309                 var type = matched && matched.name() || utilDisplayType(entity.id);
83310                 var extent = entity.extent(graph);
83311                 var distance = extent ? geoSphericalDistance(visibleCenter, extent.center()) : 0;
83312                 localResults.push({
83313                   id: entity.id,
83314                   entity: entity,
83315                   geometry: entity.geometry(graph),
83316                   type: type,
83317                   name: name,
83318                   distance: distance
83319                 });
83320                 if (localResults.length > 100) break;
83321               }
83322
83323               localResults = localResults.sort(function byDistance(a, b) {
83324                 return a.distance - b.distance;
83325               });
83326               result = result.concat(localResults);
83327
83328               (_geocodeResults || []).forEach(function (d) {
83329                 if (d.osm_type && d.osm_id) {
83330                   // some results may be missing these - #1890
83331                   // Make a temporary osmEntity so we can preset match
83332                   // and better localize the search result - #4725
83333                   var id = osmEntity.id.fromOSM(d.osm_type, d.osm_id);
83334                   var tags = {};
83335                   tags[d["class"]] = d.type;
83336                   var attrs = {
83337                     id: id,
83338                     type: d.osm_type,
83339                     tags: tags
83340                   };
83341
83342                   if (d.osm_type === 'way') {
83343                     // for ways, add some fake closed nodes
83344                     attrs.nodes = ['a', 'a']; // so that geometry area is possible
83345                   }
83346
83347                   var tempEntity = osmEntity(attrs);
83348                   var tempGraph = coreGraph([tempEntity]);
83349                   var matched = _mainPresetIndex.match(tempEntity, tempGraph);
83350                   var type = matched && matched.name() || utilDisplayType(id);
83351                   result.push({
83352                     id: tempEntity.id,
83353                     geometry: tempEntity.geometry(tempGraph),
83354                     type: type,
83355                     name: d.display_name,
83356                     extent: new geoExtent([parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])], [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
83357                   });
83358                 }
83359               });
83360
83361               if (q.match(/^[0-9]+$/)) {
83362                 // if query is just a number, possibly an OSM ID without a prefix
83363                 result.push({
83364                   id: 'n' + q,
83365                   geometry: 'point',
83366                   type: _t('inspector.node'),
83367                   name: q
83368                 });
83369                 result.push({
83370                   id: 'w' + q,
83371                   geometry: 'line',
83372                   type: _t('inspector.way'),
83373                   name: q
83374                 });
83375                 result.push({
83376                   id: 'r' + q,
83377                   geometry: 'relation',
83378                   type: _t('inspector.relation'),
83379                   name: q
83380                 });
83381               }
83382
83383               return result;
83384             }
83385
83386             function drawList() {
83387               var value = search.property('value');
83388               var results = features();
83389               list.classed('filtered', value.length);
83390               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'));
83391               resultsIndicator.append('span').attr('class', 'entity-name');
83392               list.selectAll('.no-results-item .entity-name').html(_t.html('geocoder.no_results_worldwide'));
83393
83394               if (services.geocoder) {
83395                 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'));
83396               }
83397
83398               list.selectAll('.no-results-item').style('display', value.length && !results.length ? 'block' : 'none');
83399               list.selectAll('.geocode-item').style('display', value && _geocodeResults === undefined ? 'block' : 'none');
83400               list.selectAll('.feature-list-item').data([-1]).remove();
83401               var items = list.selectAll('.feature-list-item').data(results, function (d) {
83402                 return d.id;
83403               });
83404               var enter = items.enter().insert('button', '.geocode-item').attr('class', 'feature-list-item').on('mouseover', mouseover).on('mouseout', mouseout).on('click', click);
83405               var label = enter.append('div').attr('class', 'label');
83406               label.each(function (d) {
83407                 select(this).call(svgIcon('#iD-icon-' + d.geometry, 'pre-text'));
83408               });
83409               label.append('span').attr('class', 'entity-type').html(function (d) {
83410                 return d.type;
83411               });
83412               label.append('span').attr('class', 'entity-name').html(function (d) {
83413                 return d.name;
83414               });
83415               enter.style('opacity', 0).transition().style('opacity', 1);
83416               items.order();
83417               items.exit().remove();
83418             }
83419
83420             function mouseover(d3_event, d) {
83421               if (d.id === -1) return;
83422               utilHighlightEntities([d.id], true, context);
83423             }
83424
83425             function mouseout(d3_event, d) {
83426               if (d.id === -1) return;
83427               utilHighlightEntities([d.id], false, context);
83428             }
83429
83430             function click(d3_event, d) {
83431               d3_event.preventDefault();
83432
83433               if (d.location) {
83434                 context.map().centerZoomEase([d.location[1], d.location[0]], 19);
83435               } else if (d.entity) {
83436                 utilHighlightEntities([d.id], false, context);
83437                 context.enter(modeSelect(context, [d.entity.id]));
83438                 context.map().zoomToEase(d.entity);
83439               } else {
83440                 // download, zoom to, and select the entity with the given ID
83441                 context.zoomToEntity(d.id);
83442               }
83443             }
83444
83445             function geocoderSearch() {
83446               services.geocoder.search(search.property('value'), function (err, resp) {
83447                 _geocodeResults = resp || [];
83448                 drawList();
83449               });
83450             }
83451           }
83452
83453           return featureList;
83454         }
83455
83456         function uiSectionEntityIssues(context) {
83457           var _entityIDs = [];
83458           var _issues = [];
83459
83460           var _activeIssueID;
83461
83462           var section = uiSection('entity-issues', context).shouldDisplay(function () {
83463             return _issues.length > 0;
83464           }).label(function () {
83465             return _t('inspector.title_count', {
83466               title: _t.html('issues.list_title'),
83467               count: _issues.length
83468             });
83469           }).disclosureContent(renderDisclosureContent);
83470           context.validator().on('validated.entity_issues', function () {
83471             // Refresh on validated events
83472             reloadIssues();
83473             section.reRender();
83474           }).on('focusedIssue.entity_issues', function (issue) {
83475             makeActiveIssue(issue.id);
83476           });
83477
83478           function reloadIssues() {
83479             _issues = context.validator().getSharedEntityIssues(_entityIDs, {
83480               includeDisabledRules: true
83481             });
83482           }
83483
83484           function makeActiveIssue(issueID) {
83485             _activeIssueID = issueID;
83486             section.selection().selectAll('.issue-container').classed('active', function (d) {
83487               return d.id === _activeIssueID;
83488             });
83489           }
83490
83491           function renderDisclosureContent(selection) {
83492             selection.classed('grouped-items-area', true);
83493             _activeIssueID = _issues.length > 0 ? _issues[0].id : null;
83494             var containers = selection.selectAll('.issue-container').data(_issues, function (d) {
83495               return d.id;
83496             }); // Exit
83497
83498             containers.exit().remove(); // Enter
83499
83500             var containersEnter = containers.enter().append('div').attr('class', 'issue-container');
83501             var itemsEnter = containersEnter.append('div').attr('class', function (d) {
83502               return 'issue severity-' + d.severity;
83503             }).on('mouseover.highlight', function (d3_event, d) {
83504               // don't hover-highlight the selected entity
83505               var ids = d.entityIds.filter(function (e) {
83506                 return _entityIDs.indexOf(e) === -1;
83507               });
83508               utilHighlightEntities(ids, true, context);
83509             }).on('mouseout.highlight', function (d3_event, d) {
83510               var ids = d.entityIds.filter(function (e) {
83511                 return _entityIDs.indexOf(e) === -1;
83512               });
83513               utilHighlightEntities(ids, false, context);
83514             });
83515             var labelsEnter = itemsEnter.append('div').attr('class', 'issue-label');
83516             var textEnter = labelsEnter.append('button').attr('class', 'issue-text').on('click', function (d3_event, d) {
83517               makeActiveIssue(d.id); // expand only the clicked item
83518
83519               var extent = d.extent(context.graph());
83520
83521               if (extent) {
83522                 var setZoom = Math.max(context.map().zoom(), 19);
83523                 context.map().unobscuredCenterZoomEase(extent.center(), setZoom);
83524               }
83525             });
83526             textEnter.each(function (d) {
83527               var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
83528               select(this).call(svgIcon(iconName, 'issue-icon'));
83529             });
83530             textEnter.append('span').attr('class', 'issue-message');
83531             var infoButton = labelsEnter.append('button').attr('class', 'issue-info-button').attr('title', _t('icons.information')).call(svgIcon('#iD-icon-inspect'));
83532             infoButton.on('click', function (d3_event) {
83533               d3_event.stopPropagation();
83534               d3_event.preventDefault();
83535               this.blur(); // avoid keeping focus on the button - #4641
83536
83537               var container = select(this.parentNode.parentNode.parentNode);
83538               var info = container.selectAll('.issue-info');
83539               var isExpanded = info.classed('expanded');
83540
83541               if (isExpanded) {
83542                 info.transition().duration(200).style('max-height', '0px').style('opacity', '0').on('end', function () {
83543                   info.classed('expanded', false);
83544                 });
83545               } else {
83546                 info.classed('expanded', true).transition().duration(200).style('max-height', '200px').style('opacity', '1').on('end', function () {
83547                   info.style('max-height', null);
83548                 });
83549               }
83550             });
83551             itemsEnter.append('ul').attr('class', 'issue-fix-list');
83552             containersEnter.append('div').attr('class', 'issue-info').style('max-height', '0').style('opacity', '0').each(function (d) {
83553               if (typeof d.reference === 'function') {
83554                 select(this).call(d.reference);
83555               } else {
83556                 select(this).html(_t.html('inspector.no_documentation_key'));
83557               }
83558             }); // Update
83559
83560             containers = containers.merge(containersEnter).classed('active', function (d) {
83561               return d.id === _activeIssueID;
83562             });
83563             containers.selectAll('.issue-message').html(function (d) {
83564               return d.message(context);
83565             }); // fixes
83566
83567             var fixLists = containers.selectAll('.issue-fix-list');
83568             var fixes = fixLists.selectAll('.issue-fix-item').data(function (d) {
83569               return d.fixes ? d.fixes(context) : [];
83570             }, function (fix) {
83571               return fix.id;
83572             });
83573             fixes.exit().remove();
83574             var fixesEnter = fixes.enter().append('li').attr('class', 'issue-fix-item');
83575             var buttons = fixesEnter.append('button').on('click', function (d3_event, d) {
83576               // not all fixes are actionable
83577               if (select(this).attr('disabled') || !d.onClick) return; // Don't run another fix for this issue within a second of running one
83578               // (Necessary for "Select a feature type" fix. Most fixes should only ever run once)
83579
83580               if (d.issue.dateLastRanFix && new Date() - d.issue.dateLastRanFix < 1000) return;
83581               d.issue.dateLastRanFix = new Date(); // remove hover-highlighting
83582
83583               utilHighlightEntities(d.issue.entityIds.concat(d.entityIds), false, context);
83584               new Promise(function (resolve, reject) {
83585                 d.onClick(context, resolve, reject);
83586
83587                 if (d.onClick.length <= 1) {
83588                   // if the fix doesn't take any completion parameters then consider it resolved
83589                   resolve();
83590                 }
83591               }).then(function () {
83592                 // revalidate whenever the fix has finished running successfully
83593                 context.validator().validate();
83594               });
83595             }).on('mouseover.highlight', function (d3_event, d) {
83596               utilHighlightEntities(d.entityIds, true, context);
83597             }).on('mouseout.highlight', function (d3_event, d) {
83598               utilHighlightEntities(d.entityIds, false, context);
83599             });
83600             buttons.each(function (d) {
83601               var iconName = d.icon || 'iD-icon-wrench';
83602
83603               if (iconName.startsWith('maki')) {
83604                 iconName += '-15';
83605               }
83606
83607               select(this).call(svgIcon('#' + iconName, 'fix-icon'));
83608             });
83609             buttons.append('span').attr('class', 'fix-message').html(function (d) {
83610               return d.title;
83611             });
83612             fixesEnter.merge(fixes).selectAll('button').classed('actionable', function (d) {
83613               return d.onClick;
83614             }).attr('disabled', function (d) {
83615               return d.onClick ? null : 'true';
83616             }).attr('title', function (d) {
83617               if (d.disabledReason) {
83618                 return d.disabledReason;
83619               }
83620
83621               return null;
83622             });
83623           }
83624
83625           section.entityIDs = function (val) {
83626             if (!arguments.length) return _entityIDs;
83627
83628             if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
83629               _entityIDs = val;
83630               _activeIssueID = null;
83631               reloadIssues();
83632             }
83633
83634             return section;
83635           };
83636
83637           return section;
83638         }
83639
83640         function uiPresetIcon() {
83641           var _preset;
83642
83643           var _geometry;
83644
83645           var _sizeClass = 'medium';
83646
83647           function isSmall() {
83648             return _sizeClass === 'small';
83649           }
83650
83651           function presetIcon(selection) {
83652             selection.each(render);
83653           }
83654
83655           function getIcon(p, geom) {
83656             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';
83657           }
83658
83659           function renderPointBorder(container, drawPoint) {
83660             var pointBorder = container.selectAll('.preset-icon-point-border').data(drawPoint ? [0] : []);
83661             pointBorder.exit().remove();
83662             var pointBorderEnter = pointBorder.enter();
83663             var w = 40;
83664             var h = 40;
83665             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');
83666             pointBorder = pointBorderEnter.merge(pointBorder);
83667           }
83668
83669           function renderCircleFill(container, drawVertex) {
83670             var vertexFill = container.selectAll('.preset-icon-fill-vertex').data(drawVertex ? [0] : []);
83671             vertexFill.exit().remove();
83672             var vertexFillEnter = vertexFill.enter();
83673             var w = 60;
83674             var h = 60;
83675             var d = 40;
83676             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);
83677             vertexFill = vertexFillEnter.merge(vertexFill);
83678           }
83679
83680           function renderSquareFill(container, drawArea, tagClasses) {
83681             var fill = container.selectAll('.preset-icon-fill-area').data(drawArea ? [0] : []);
83682             fill.exit().remove();
83683             var fillEnter = fill.enter();
83684             var d = isSmall() ? 40 : 60;
83685             var w = d;
83686             var h = d;
83687             var l = d * 2 / 3;
83688             var c1 = (w - l) / 2;
83689             var c2 = c1 + l;
83690             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));
83691             ['fill', 'stroke'].forEach(function (klass) {
83692               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));
83693             });
83694             var rVertex = 2.5;
83695             [[c1, c1], [c1, c2], [c2, c2], [c2, c1]].forEach(function (point) {
83696               fillEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', rVertex);
83697             });
83698
83699             if (!isSmall()) {
83700               var rMidpoint = 1.25;
83701               [[c1, w / 2], [c2, w / 2], [h / 2, c1], [h / 2, c2]].forEach(function (point) {
83702                 fillEnter.append('circle').attr('class', 'midpoint').attr('cx', point[0]).attr('cy', point[1]).attr('r', rMidpoint);
83703               });
83704             }
83705
83706             fill = fillEnter.merge(fill);
83707             fill.selectAll('path.stroke').attr('class', "area stroke ".concat(tagClasses));
83708             fill.selectAll('path.fill').attr('class', "area fill ".concat(tagClasses));
83709           }
83710
83711           function renderLine(container, drawLine, tagClasses) {
83712             var line = container.selectAll('.preset-icon-line').data(drawLine ? [0] : []);
83713             line.exit().remove();
83714             var lineEnter = line.enter();
83715             var d = isSmall() ? 40 : 60; // draw the line parametrically
83716
83717             var w = d;
83718             var h = d;
83719             var y = Math.round(d * 0.72);
83720             var l = Math.round(d * 0.6);
83721             var r = 2.5;
83722             var x1 = (w - l) / 2;
83723             var x2 = x1 + l;
83724             lineEnter = lineEnter.append('svg').attr('class', 'preset-icon-line').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
83725             ['casing', 'stroke'].forEach(function (klass) {
83726               lineEnter.append('path').attr('d', "M".concat(x1, " ").concat(y, " L").concat(x2, " ").concat(y)).attr('class', "line ".concat(klass));
83727             });
83728             [[x1 - 1, y], [x2 + 1, y]].forEach(function (point) {
83729               lineEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', r);
83730             });
83731             line = lineEnter.merge(line);
83732             line.selectAll('path.stroke').attr('class', "line stroke ".concat(tagClasses));
83733             line.selectAll('path.casing').attr('class', "line casing ".concat(tagClasses));
83734           }
83735
83736           function renderRoute(container, drawRoute, p) {
83737             var route = container.selectAll('.preset-icon-route').data(drawRoute ? [0] : []);
83738             route.exit().remove();
83739             var routeEnter = route.enter();
83740             var d = isSmall() ? 40 : 60; // draw the route parametrically
83741
83742             var w = d;
83743             var h = d;
83744             var y1 = Math.round(d * 0.80);
83745             var y2 = Math.round(d * 0.68);
83746             var l = Math.round(d * 0.6);
83747             var r = 2;
83748             var x1 = (w - l) / 2;
83749             var x2 = x1 + l / 3;
83750             var x3 = x2 + l / 3;
83751             var x4 = x3 + l / 3;
83752             routeEnter = routeEnter.append('svg').attr('class', 'preset-icon-route').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
83753             ['casing', 'stroke'].forEach(function (klass) {
83754               routeEnter.append('path').attr('d', "M".concat(x1, " ").concat(y1, " L").concat(x2, " ").concat(y2)).attr('class', "segment0 line ".concat(klass));
83755               routeEnter.append('path').attr('d', "M".concat(x2, " ").concat(y2, " L").concat(x3, " ").concat(y1)).attr('class', "segment1 line ".concat(klass));
83756               routeEnter.append('path').attr('d', "M".concat(x3, " ").concat(y1, " L").concat(x4, " ").concat(y2)).attr('class', "segment2 line ".concat(klass));
83757             });
83758             [[x1, y1], [x2, y2], [x3, y1], [x4, y2]].forEach(function (point) {
83759               routeEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', r);
83760             });
83761             route = routeEnter.merge(route);
83762
83763             if (drawRoute) {
83764               var routeType = p.tags.type === 'waterway' ? 'waterway' : p.tags.route;
83765               var segmentPresetIDs = routeSegments[routeType];
83766
83767               for (var i in segmentPresetIDs) {
83768                 var segmentPreset = _mainPresetIndex.item(segmentPresetIDs[i]);
83769                 var segmentTagClasses = svgTagClasses().getClassesString(segmentPreset.tags, '');
83770                 route.selectAll("path.stroke.segment".concat(i)).attr('class', "segment".concat(i, " line stroke ").concat(segmentTagClasses));
83771                 route.selectAll("path.casing.segment".concat(i)).attr('class', "segment".concat(i, " line casing ").concat(segmentTagClasses));
83772               }
83773             }
83774           } // Route icons are drawn with a zigzag annotation underneath:
83775           //     o   o
83776           //    / \ /
83777           //   o   o
83778           // This dataset defines the styles that are used to draw the zigzag segments.
83779
83780
83781           var routeSegments = {
83782             bicycle: ['highway/cycleway', 'highway/cycleway', 'highway/cycleway'],
83783             bus: ['highway/unclassified', 'highway/secondary', 'highway/primary'],
83784             trolleybus: ['highway/unclassified', 'highway/secondary', 'highway/primary'],
83785             detour: ['highway/tertiary', 'highway/residential', 'highway/unclassified'],
83786             ferry: ['route/ferry', 'route/ferry', 'route/ferry'],
83787             foot: ['highway/footway', 'highway/footway', 'highway/footway'],
83788             hiking: ['highway/path', 'highway/path', 'highway/path'],
83789             horse: ['highway/bridleway', 'highway/bridleway', 'highway/bridleway'],
83790             light_rail: ['railway/light_rail', 'railway/light_rail', 'railway/light_rail'],
83791             monorail: ['railway/monorail', 'railway/monorail', 'railway/monorail'],
83792             pipeline: ['man_made/pipeline', 'man_made/pipeline', 'man_made/pipeline'],
83793             piste: ['piste/downhill', 'piste/hike', 'piste/nordic'],
83794             power: ['power/line', 'power/line', 'power/line'],
83795             road: ['highway/secondary', 'highway/primary', 'highway/trunk'],
83796             subway: ['railway/subway', 'railway/subway', 'railway/subway'],
83797             train: ['railway/rail', 'railway/rail', 'railway/rail'],
83798             tram: ['railway/tram', 'railway/tram', 'railway/tram'],
83799             waterway: ['waterway/stream', 'waterway/stream', 'waterway/stream']
83800           };
83801
83802           function render() {
83803             var p = _preset.apply(this, arguments);
83804
83805             var geom = _geometry ? _geometry.apply(this, arguments) : null;
83806
83807             if (geom === 'relation' && p.tags && (p.tags.type === 'route' && p.tags.route && routeSegments[p.tags.route] || p.tags.type === 'waterway')) {
83808               geom = 'route';
83809             }
83810
83811             var showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
83812             var isFallback = isSmall() && p.isFallback && p.isFallback();
83813             var imageURL = showThirdPartyIcons === 'true' && p.imageURL;
83814             var picon = getIcon(p, geom);
83815             var isMaki = picon && /^maki-/.test(picon);
83816             var isTemaki = picon && /^temaki-/.test(picon);
83817             var isFa = picon && /^fa[srb]-/.test(picon);
83818             var isiDIcon = picon && !(isMaki || isTemaki || isFa);
83819             var isCategory = !p.setTags;
83820             var drawPoint = picon && geom === 'point' && isSmall() && !isFallback;
83821             var drawVertex = picon !== null && geom === 'vertex' && (!isSmall() || !isFallback);
83822             var drawLine = picon && geom === 'line' && !isFallback && !isCategory;
83823             var drawArea = picon && geom === 'area' && !isFallback;
83824             var drawRoute = picon && geom === 'route';
83825             var isFramed = drawVertex || drawArea || drawLine || drawRoute;
83826             var tags = !isCategory ? p.setTags({}, geom) : {};
83827
83828             for (var k in tags) {
83829               if (tags[k] === '*') {
83830                 tags[k] = 'yes';
83831               }
83832             }
83833
83834             var tagClasses = svgTagClasses().getClassesString(tags, '');
83835             var selection = select(this);
83836             var container = selection.selectAll('.preset-icon-container').data([0]);
83837             container = container.enter().append('div').attr('class', "preset-icon-container ".concat(_sizeClass)).merge(container);
83838             container.classed('showing-img', !!imageURL).classed('fallback', isFallback);
83839             renderPointBorder(container, drawPoint);
83840             renderCircleFill(container, drawVertex);
83841             renderSquareFill(container, drawArea, tagClasses);
83842             renderLine(container, drawLine, tagClasses);
83843             renderRoute(container, drawRoute, p);
83844             var icon = container.selectAll('.preset-icon').data(picon ? [0] : []);
83845             icon.exit().remove();
83846             icon = icon.enter().append('div').attr('class', 'preset-icon').call(svgIcon('')).merge(icon);
83847             icon.attr('class', 'preset-icon ' + (geom ? geom + '-geom' : '')).classed('framed', isFramed).classed('preset-icon-iD', isiDIcon);
83848             icon.selectAll('svg').attr('class', 'icon ' + picon + ' ' + (!isiDIcon && geom !== 'line' ? '' : tagClasses));
83849             icon.selectAll('use').attr('href', '#' + picon + (isMaki ? isSmall() && geom === 'point' ? '-11' : '-15' : ''));
83850             var imageIcon = container.selectAll('img.image-icon').data(imageURL ? [0] : []);
83851             imageIcon.exit().remove();
83852             imageIcon = imageIcon.enter().append('img').attr('class', 'image-icon').on('load', function () {
83853               return container.classed('showing-img', true);
83854             }).on('error', function () {
83855               return container.classed('showing-img', false);
83856             }).merge(imageIcon);
83857             imageIcon.attr('src', imageURL);
83858           }
83859
83860           presetIcon.preset = function (val) {
83861             if (!arguments.length) return _preset;
83862             _preset = utilFunctor(val);
83863             return presetIcon;
83864           };
83865
83866           presetIcon.geometry = function (val) {
83867             if (!arguments.length) return _geometry;
83868             _geometry = utilFunctor(val);
83869             return presetIcon;
83870           };
83871
83872           presetIcon.sizeClass = function (val) {
83873             if (!arguments.length) return _sizeClass;
83874             _sizeClass = val;
83875             return presetIcon;
83876           };
83877
83878           return presetIcon;
83879         }
83880
83881         function uiSectionFeatureType(context) {
83882           var dispatch$1 = dispatch('choose');
83883           var _entityIDs = [];
83884           var _presets = [];
83885
83886           var _tagReference;
83887
83888           var section = uiSection('feature-type', context).label(_t.html('inspector.feature_type')).disclosureContent(renderDisclosureContent);
83889
83890           function renderDisclosureContent(selection) {
83891             selection.classed('preset-list-item', true);
83892             selection.classed('mixed-types', _presets.length > 1);
83893             var presetButtonWrap = selection.selectAll('.preset-list-button-wrap').data([0]).enter().append('div').attr('class', 'preset-list-button-wrap');
83894             var presetButton = presetButtonWrap.append('button').attr('class', 'preset-list-button preset-reset').call(uiTooltip().title(_t.html('inspector.back_tooltip')).placement('bottom'));
83895             presetButton.append('div').attr('class', 'preset-icon-container');
83896             presetButton.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
83897             presetButtonWrap.append('div').attr('class', 'accessory-buttons');
83898             var tagReferenceBodyWrap = selection.selectAll('.tag-reference-body-wrap').data([0]);
83899             tagReferenceBodyWrap = tagReferenceBodyWrap.enter().append('div').attr('class', 'tag-reference-body-wrap').merge(tagReferenceBodyWrap); // update header
83900
83901             if (_tagReference) {
83902               selection.selectAll('.preset-list-button-wrap .accessory-buttons').style('display', _presets.length === 1 ? null : 'none').call(_tagReference.button);
83903               tagReferenceBodyWrap.style('display', _presets.length === 1 ? null : 'none').call(_tagReference.body);
83904             }
83905
83906             selection.selectAll('.preset-reset').on('click', function () {
83907               dispatch$1.call('choose', this, _presets);
83908             }).on('pointerdown pointerup mousedown mouseup', function (d3_event) {
83909               d3_event.preventDefault();
83910               d3_event.stopPropagation();
83911             });
83912             var geometries = entityGeometries();
83913             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')));
83914             var names = _presets.length === 1 ? [_presets[0].nameLabel(), _presets[0].subtitleLabel()].filter(Boolean) : [_t('inspector.multiple_types')];
83915             var label = selection.select('.label-inner');
83916             var nameparts = label.selectAll('.namepart').data(names, function (d) {
83917               return d;
83918             });
83919             nameparts.exit().remove();
83920             nameparts.enter().append('div').attr('class', 'namepart').html(function (d) {
83921               return d;
83922             });
83923           }
83924
83925           section.entityIDs = function (val) {
83926             if (!arguments.length) return _entityIDs;
83927             _entityIDs = val;
83928             return section;
83929           };
83930
83931           section.presets = function (val) {
83932             if (!arguments.length) return _presets; // don't reload the same preset
83933
83934             if (!utilArrayIdentical(val, _presets)) {
83935               _presets = val;
83936
83937               if (_presets.length === 1) {
83938                 _tagReference = uiTagReference(_presets[0].reference()).showing(false);
83939               }
83940             }
83941
83942             return section;
83943           };
83944
83945           function entityGeometries() {
83946             var counts = {};
83947
83948             for (var i in _entityIDs) {
83949               var geometry = context.graph().geometry(_entityIDs[i]);
83950               if (!counts[geometry]) counts[geometry] = 0;
83951               counts[geometry] += 1;
83952             }
83953
83954             return Object.keys(counts).sort(function (geom1, geom2) {
83955               return counts[geom2] - counts[geom1];
83956             });
83957           }
83958
83959           return utilRebind(section, dispatch$1, 'on');
83960         }
83961
83962         // It borrows some code from uiHelp
83963
83964         function uiFieldHelp(context, fieldName) {
83965           var fieldHelp = {};
83966
83967           var _inspector = select(null);
83968
83969           var _wrap = select(null);
83970
83971           var _body = select(null);
83972
83973           var fieldHelpKeys = {
83974             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']]]
83975           };
83976           var fieldHelpHeadings = {};
83977           var replacements = {
83978             distField: _t.html('restriction.controls.distance'),
83979             viaField: _t.html('restriction.controls.via'),
83980             fromShadow: icon('#iD-turn-shadow', 'inline shadow from'),
83981             allowShadow: icon('#iD-turn-shadow', 'inline shadow allow'),
83982             restrictShadow: icon('#iD-turn-shadow', 'inline shadow restrict'),
83983             onlyShadow: icon('#iD-turn-shadow', 'inline shadow only'),
83984             allowTurn: icon('#iD-turn-yes', 'inline turn'),
83985             restrictTurn: icon('#iD-turn-no', 'inline turn'),
83986             onlyTurn: icon('#iD-turn-only', 'inline turn')
83987           }; // For each section, squash all the texts into a single markdown document
83988
83989           var docs = fieldHelpKeys[fieldName].map(function (key) {
83990             var helpkey = 'help.field.' + fieldName + '.' + key[0];
83991             var text = key[1].reduce(function (all, part) {
83992               var subkey = helpkey + '.' + part;
83993               var depth = fieldHelpHeadings[subkey]; // is this subkey a heading?
83994
83995               var hhh = depth ? Array(depth + 1).join('#') + ' ' : ''; // if so, prepend with some ##'s
83996
83997               return all + hhh + _t.html(subkey, replacements) + '\n\n';
83998             }, '');
83999             return {
84000               key: helpkey,
84001               title: _t.html(helpkey + '.title'),
84002               html: marked_1(text.trim())
84003             };
84004           });
84005
84006           function show() {
84007             updatePosition();
84008
84009             _body.classed('hide', false).style('opacity', '0').transition().duration(200).style('opacity', '1');
84010           }
84011
84012           function hide() {
84013             _body.classed('hide', true).transition().duration(200).style('opacity', '0').on('end', function () {
84014               _body.classed('hide', true);
84015             });
84016           }
84017
84018           function clickHelp(index) {
84019             var d = docs[index];
84020             var tkeys = fieldHelpKeys[fieldName][index][1];
84021
84022             _body.selectAll('.field-help-nav-item').classed('active', function (d, i) {
84023               return i === index;
84024             });
84025
84026             var content = _body.selectAll('.field-help-content').html(d.html); // class the paragraphs so we can find and style them
84027
84028
84029             content.selectAll('p').attr('class', function (d, i) {
84030               return tkeys[i];
84031             }); // insert special content for certain help sections
84032
84033             if (d.key === 'help.field.restrictions.inspecting') {
84034               content.insert('img', 'p.from_shadow').attr('class', 'field-help-image cf').attr('src', context.imagePath('tr_inspect.gif'));
84035             } else if (d.key === 'help.field.restrictions.modifying') {
84036               content.insert('img', 'p.allow_turn').attr('class', 'field-help-image cf').attr('src', context.imagePath('tr_modify.gif'));
84037             }
84038           }
84039
84040           fieldHelp.button = function (selection) {
84041             if (_body.empty()) return;
84042             var button = selection.selectAll('.field-help-button').data([0]); // enter/update
84043
84044             button.enter().append('button').attr('class', 'field-help-button').call(svgIcon('#iD-icon-help')).merge(button).on('click', function (d3_event) {
84045               d3_event.stopPropagation();
84046               d3_event.preventDefault();
84047
84048               if (_body.classed('hide')) {
84049                 show();
84050               } else {
84051                 hide();
84052               }
84053             });
84054           };
84055
84056           function updatePosition() {
84057             var wrap = _wrap.node();
84058
84059             var inspector = _inspector.node();
84060
84061             var wRect = wrap.getBoundingClientRect();
84062             var iRect = inspector.getBoundingClientRect();
84063
84064             _body.style('top', wRect.top + inspector.scrollTop - iRect.top + 'px');
84065           }
84066
84067           fieldHelp.body = function (selection) {
84068             // This control expects the field to have a form-field-input-wrap div
84069             _wrap = selection.selectAll('.form-field-input-wrap');
84070             if (_wrap.empty()) return; // absolute position relative to the inspector, so it "floats" above the fields
84071
84072             _inspector = context.container().select('.sidebar .entity-editor-pane .inspector-body');
84073             if (_inspector.empty()) return;
84074             _body = _inspector.selectAll('.field-help-body').data([0]);
84075
84076             var enter = _body.enter().append('div').attr('class', 'field-help-body hide'); // initially hidden
84077
84078
84079             var titleEnter = enter.append('div').attr('class', 'field-help-title cf');
84080             titleEnter.append('h2').attr('class', _mainLocalizer.textDirection() === 'rtl' ? 'fr' : 'fl').html(_t.html('help.field.' + fieldName + '.title'));
84081             titleEnter.append('button').attr('class', 'fr close').on('click', function (d3_event) {
84082               d3_event.stopPropagation();
84083               d3_event.preventDefault();
84084               hide();
84085             }).call(svgIcon('#iD-icon-close'));
84086             var navEnter = enter.append('div').attr('class', 'field-help-nav cf');
84087             var titles = docs.map(function (d) {
84088               return d.title;
84089             });
84090             navEnter.selectAll('.field-help-nav-item').data(titles).enter().append('div').attr('class', 'field-help-nav-item').html(function (d) {
84091               return d;
84092             }).on('click', function (d3_event, d) {
84093               d3_event.stopPropagation();
84094               d3_event.preventDefault();
84095               clickHelp(titles.indexOf(d));
84096             });
84097             enter.append('div').attr('class', 'field-help-content');
84098             _body = _body.merge(enter);
84099             clickHelp(0);
84100           };
84101
84102           return fieldHelp;
84103         }
84104
84105         function uiFieldCheck(field, context) {
84106           var dispatch$1 = dispatch('change');
84107           var options = field.strings && field.strings.options;
84108           var values = [];
84109           var texts = [];
84110
84111           var _tags;
84112
84113           var input = select(null);
84114           var text = select(null);
84115           var label = select(null);
84116           var reverser = select(null);
84117
84118           var _impliedYes;
84119
84120           var _entityIDs = [];
84121
84122           var _value;
84123
84124           if (options) {
84125             for (var k in options) {
84126               values.push(k === 'undefined' ? undefined : k);
84127               texts.push(field.t.html('options.' + k, {
84128                 'default': options[k]
84129               }));
84130             }
84131           } else {
84132             values = [undefined, 'yes'];
84133             texts = [_t.html('inspector.unknown'), _t.html('inspector.check.yes')];
84134
84135             if (field.type !== 'defaultCheck') {
84136               values.push('no');
84137               texts.push(_t.html('inspector.check.no'));
84138             }
84139           } // Checks tags to see whether an undefined value is "Assumed to be Yes"
84140
84141
84142           function checkImpliedYes() {
84143             _impliedYes = field.id === 'oneway_yes'; // hack: pretend `oneway` field is a `oneway_yes` field
84144             // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
84145
84146             if (field.id === 'oneway') {
84147               var entity = context.entity(_entityIDs[0]);
84148
84149               for (var key in entity.tags) {
84150                 if (key in osmOneWayTags && entity.tags[key] in osmOneWayTags[key]) {
84151                   _impliedYes = true;
84152                   texts[0] = _t.html('presets.fields.oneway_yes.options.undefined');
84153                   break;
84154                 }
84155               }
84156             }
84157           }
84158
84159           function reverserHidden() {
84160             if (!context.container().select('div.inspector-hover').empty()) return true;
84161             return !(_value === 'yes' || _impliedYes && !_value);
84162           }
84163
84164           function reverserSetText(selection) {
84165             var entity = _entityIDs.length && context.hasEntity(_entityIDs[0]);
84166             if (reverserHidden() || !entity) return selection;
84167             var first = entity.first();
84168             var last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last();
84169             var pseudoDirection = first < last;
84170             var icon = pseudoDirection ? '#iD-icon-forward' : '#iD-icon-backward';
84171             selection.selectAll('.reverser-span').html(_t.html('inspector.check.reverser')).call(svgIcon(icon, 'inline'));
84172             return selection;
84173           }
84174
84175           var check = function check(selection) {
84176             checkImpliedYes();
84177             label = selection.selectAll('.form-field-input-wrap').data([0]);
84178             var enter = label.enter().append('label').attr('class', 'form-field-input-wrap form-field-input-check');
84179             enter.append('input').property('indeterminate', field.type !== 'defaultCheck').attr('type', 'checkbox').attr('id', field.domId);
84180             enter.append('span').html(texts[0]).attr('class', 'value');
84181
84182             if (field.type === 'onewayCheck') {
84183               enter.append('button').attr('class', 'reverser' + (reverserHidden() ? ' hide' : '')).append('span').attr('class', 'reverser-span');
84184             }
84185
84186             label = label.merge(enter);
84187             input = label.selectAll('input');
84188             text = label.selectAll('span.value');
84189             input.on('click', function (d3_event) {
84190               d3_event.stopPropagation();
84191               var t = {};
84192
84193               if (Array.isArray(_tags[field.key])) {
84194                 if (values.indexOf('yes') !== -1) {
84195                   t[field.key] = 'yes';
84196                 } else {
84197                   t[field.key] = values[0];
84198                 }
84199               } else {
84200                 t[field.key] = values[(values.indexOf(_value) + 1) % values.length];
84201               } // Don't cycle through `alternating` or `reversible` states - #4970
84202               // (They are supported as translated strings, but should not toggle with clicks)
84203
84204
84205               if (t[field.key] === 'reversible' || t[field.key] === 'alternating') {
84206                 t[field.key] = values[0];
84207               }
84208
84209               dispatch$1.call('change', this, t);
84210             });
84211
84212             if (field.type === 'onewayCheck') {
84213               reverser = label.selectAll('.reverser');
84214               reverser.call(reverserSetText).on('click', function (d3_event) {
84215                 d3_event.preventDefault();
84216                 d3_event.stopPropagation();
84217                 context.perform(function (graph) {
84218                   for (var i in _entityIDs) {
84219                     graph = actionReverse(_entityIDs[i])(graph);
84220                   }
84221
84222                   return graph;
84223                 }, _t('operations.reverse.annotation.line', {
84224                   n: 1
84225                 })); // must manually revalidate since no 'change' event was called
84226
84227                 context.validator().validate();
84228                 select(this).call(reverserSetText);
84229               });
84230             }
84231           };
84232
84233           check.entityIDs = function (val) {
84234             if (!arguments.length) return _entityIDs;
84235             _entityIDs = val;
84236             return check;
84237           };
84238
84239           check.tags = function (tags) {
84240             _tags = tags;
84241
84242             function isChecked(val) {
84243               return val !== 'no' && val !== '' && val !== undefined && val !== null;
84244             }
84245
84246             function textFor(val) {
84247               if (val === '') val = undefined;
84248               var index = values.indexOf(val);
84249               return index !== -1 ? texts[index] : '"' + val + '"';
84250             }
84251
84252             checkImpliedYes();
84253             var isMixed = Array.isArray(tags[field.key]);
84254             _value = !isMixed && tags[field.key] && tags[field.key].toLowerCase();
84255
84256             if (field.type === 'onewayCheck' && (_value === '1' || _value === '-1')) {
84257               _value = 'yes';
84258             }
84259
84260             input.property('indeterminate', isMixed || field.type !== 'defaultCheck' && !_value).property('checked', isChecked(_value));
84261             text.html(isMixed ? _t.html('inspector.multiple_values') : textFor(_value)).classed('mixed', isMixed);
84262             label.classed('set', !!_value);
84263
84264             if (field.type === 'onewayCheck') {
84265               reverser.classed('hide', reverserHidden()).call(reverserSetText);
84266             }
84267           };
84268
84269           check.focus = function () {
84270             input.node().focus();
84271           };
84272
84273           return utilRebind(check, dispatch$1, 'on');
84274         }
84275
84276         function uiFieldCombo(field, context) {
84277           var dispatch$1 = dispatch('change');
84278
84279           var _isMulti = field.type === 'multiCombo' || field.type === 'manyCombo';
84280
84281           var _isNetwork = field.type === 'networkCombo';
84282
84283           var _isSemi = field.type === 'semiCombo';
84284
84285           var _optstrings = field.strings && field.strings.options;
84286
84287           var _optarray = field.options;
84288
84289           var _snake_case = field.snake_case || field.snake_case === undefined;
84290
84291           var _combobox = uiCombobox(context, 'combo-' + field.safeid).caseSensitive(field.caseSensitive).minItems(_isMulti || _isSemi ? 1 : 2);
84292
84293           var _container = select(null);
84294
84295           var _inputWrap = select(null);
84296
84297           var _input = select(null);
84298
84299           var _comboData = [];
84300           var _multiData = [];
84301           var _entityIDs = [];
84302
84303           var _tags;
84304
84305           var _countryCode;
84306
84307           var _staticPlaceholder; // initialize deprecated tags array
84308
84309
84310           var _dataDeprecated = [];
84311           _mainFileFetcher.get('deprecated').then(function (d) {
84312             _dataDeprecated = d;
84313           })["catch"](function () {
84314             /* ignore */
84315           }); // ensure multiCombo field.key ends with a ':'
84316
84317           if (_isMulti && field.key && /[^:]$/.test(field.key)) {
84318             field.key += ':';
84319           }
84320
84321           function snake(s) {
84322             return s.replace(/\s+/g, '_');
84323           }
84324
84325           function unsnake(s) {
84326             return s.replace(/_+/g, ' ');
84327           }
84328
84329           function clean(s) {
84330             return s.split(';').map(function (s) {
84331               return s.trim();
84332             }).join(';');
84333           } // returns the tag value for a display value
84334           // (for multiCombo, dval should be the key suffix, not the entire key)
84335
84336
84337           function tagValue(dval) {
84338             dval = clean(dval || '');
84339
84340             if (_optstrings) {
84341               var found = _comboData.find(function (o) {
84342                 return o.key && clean(o.value) === dval;
84343               });
84344
84345               if (found) {
84346                 return found.key;
84347               }
84348             }
84349
84350             if (field.type === 'typeCombo' && !dval) {
84351               return 'yes';
84352             }
84353
84354             return (_snake_case ? snake(dval) : dval) || undefined;
84355           } // returns the display value for a tag value
84356           // (for multiCombo, tval should be the key suffix, not the entire key)
84357
84358
84359           function displayValue(tval) {
84360             tval = tval || '';
84361
84362             if (_optstrings) {
84363               var found = _comboData.find(function (o) {
84364                 return o.key === tval && o.value;
84365               });
84366
84367               if (found) {
84368                 return found.value;
84369               }
84370             }
84371
84372             if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
84373               return '';
84374             }
84375
84376             return _snake_case ? unsnake(tval) : tval;
84377           } // Compute the difference between arrays of objects by `value` property
84378           //
84379           // objectDifference([{value:1}, {value:2}, {value:3}], [{value:2}])
84380           // > [{value:1}, {value:3}]
84381           //
84382
84383
84384           function objectDifference(a, b) {
84385             return a.filter(function (d1) {
84386               return !b.some(function (d2) {
84387                 return !d2.isMixed && d1.value === d2.value;
84388               });
84389             });
84390           }
84391
84392           function initCombo(selection, attachTo) {
84393             if (_optstrings) {
84394               selection.attr('readonly', 'readonly');
84395               selection.call(_combobox, attachTo);
84396               setStaticValues(setPlaceholder);
84397             } else if (_optarray) {
84398               selection.call(_combobox, attachTo);
84399               setStaticValues(setPlaceholder);
84400             } else if (services.taginfo) {
84401               selection.call(_combobox.fetcher(setTaginfoValues), attachTo);
84402               setTaginfoValues('', setPlaceholder);
84403             }
84404           }
84405
84406           function setStaticValues(callback) {
84407             if (!(_optstrings || _optarray)) return;
84408
84409             if (_optstrings) {
84410               _comboData = Object.keys(_optstrings).map(function (k) {
84411                 var v = field.t('options.' + k, {
84412                   'default': _optstrings[k]
84413                 });
84414                 return {
84415                   key: k,
84416                   value: v,
84417                   title: v,
84418                   display: field.t.html('options.' + k, {
84419                     'default': _optstrings[k]
84420                   })
84421                 };
84422               });
84423             } else if (_optarray) {
84424               _comboData = _optarray.map(function (k) {
84425                 var v = _snake_case ? unsnake(k) : k;
84426                 return {
84427                   key: k,
84428                   value: v,
84429                   title: v
84430                 };
84431               });
84432             }
84433
84434             _combobox.data(objectDifference(_comboData, _multiData));
84435
84436             if (callback) callback(_comboData);
84437           }
84438
84439           function setTaginfoValues(q, callback) {
84440             var fn = _isMulti ? 'multikeys' : 'values';
84441             var query = (_isMulti ? field.key : '') + q;
84442             var hasCountryPrefix = _isNetwork && _countryCode && _countryCode.indexOf(q.toLowerCase()) === 0;
84443
84444             if (hasCountryPrefix) {
84445               query = _countryCode + ':';
84446             }
84447
84448             var params = {
84449               debounce: q !== '',
84450               key: field.key,
84451               query: query
84452             };
84453
84454             if (_entityIDs.length) {
84455               params.geometry = context.graph().geometry(_entityIDs[0]);
84456             }
84457
84458             services.taginfo[fn](params, function (err, data) {
84459               if (err) return;
84460               data = data.filter(function (d) {
84461                 if (field.type === 'typeCombo' && d.value === 'yes') {
84462                   // don't show the fallback value
84463                   return false;
84464                 } // don't show values with very low usage
84465
84466
84467                 return !d.count || d.count > 10;
84468               });
84469               var deprecatedValues = osmEntity.deprecatedTagValuesByKey(_dataDeprecated)[field.key];
84470
84471               if (deprecatedValues) {
84472                 // don't suggest deprecated tag values
84473                 data = data.filter(function (d) {
84474                   return deprecatedValues.indexOf(d.value) === -1;
84475                 });
84476               }
84477
84478               if (hasCountryPrefix) {
84479                 data = data.filter(function (d) {
84480                   return d.value.toLowerCase().indexOf(_countryCode + ':') === 0;
84481                 });
84482               } // hide the caret if there are no suggestions
84483
84484
84485               _container.classed('empty-combobox', data.length === 0);
84486
84487               _comboData = data.map(function (d) {
84488                 var k = d.value;
84489                 if (_isMulti) k = k.replace(field.key, '');
84490                 var v = _snake_case ? unsnake(k) : k;
84491                 return {
84492                   key: k,
84493                   value: v,
84494                   title: _isMulti ? v : d.title
84495                 };
84496               });
84497               _comboData = objectDifference(_comboData, _multiData);
84498               if (callback) callback(_comboData);
84499             });
84500           }
84501
84502           function setPlaceholder(values) {
84503             if (_isMulti || _isSemi) {
84504               _staticPlaceholder = field.placeholder() || _t('inspector.add');
84505             } else {
84506               var vals = values.map(function (d) {
84507                 return d.value;
84508               }).filter(function (s) {
84509                 return s.length < 20;
84510               });
84511               var placeholders = vals.length > 1 ? vals : values.map(function (d) {
84512                 return d.key;
84513               });
84514               _staticPlaceholder = field.placeholder() || placeholders.slice(0, 3).join(', ');
84515             }
84516
84517             if (!/(…|\.\.\.)$/.test(_staticPlaceholder)) {
84518               _staticPlaceholder += '…';
84519             }
84520
84521             var ph;
84522
84523             if (!_isMulti && !_isSemi && _tags && Array.isArray(_tags[field.key])) {
84524               ph = _t('inspector.multiple_values');
84525             } else {
84526               ph = _staticPlaceholder;
84527             }
84528
84529             _container.selectAll('input').attr('placeholder', ph);
84530           }
84531
84532           function change() {
84533             var t = {};
84534             var val;
84535
84536             if (_isMulti || _isSemi) {
84537               val = tagValue(utilGetSetValue(_input).replace(/,/g, ';')) || '';
84538
84539               _container.classed('active', false);
84540
84541               utilGetSetValue(_input, '');
84542               var vals = val.split(';').filter(Boolean);
84543               if (!vals.length) return;
84544
84545               if (_isMulti) {
84546                 utilArrayUniq(vals).forEach(function (v) {
84547                   var key = (field.key || '') + v;
84548
84549                   if (_tags) {
84550                     // don't set a multicombo value to 'yes' if it already has a non-'no' value
84551                     // e.g. `language:de=main`
84552                     var old = _tags[key];
84553                     if (typeof old === 'string' && old.toLowerCase() !== 'no') return;
84554                   }
84555
84556                   key = context.cleanTagKey(key);
84557                   field.keys.push(key);
84558                   t[key] = 'yes';
84559                 });
84560               } else if (_isSemi) {
84561                 var arr = _multiData.map(function (d) {
84562                   return d.key;
84563                 });
84564
84565                 arr = arr.concat(vals);
84566                 t[field.key] = context.cleanTagValue(utilArrayUniq(arr).filter(Boolean).join(';'));
84567               }
84568
84569               window.setTimeout(function () {
84570                 _input.node().focus();
84571               }, 10);
84572             } else {
84573               var rawValue = utilGetSetValue(_input); // don't override multiple values with blank string
84574
84575               if (!rawValue && Array.isArray(_tags[field.key])) return;
84576               val = context.cleanTagValue(tagValue(rawValue));
84577               t[field.key] = val || undefined;
84578             }
84579
84580             dispatch$1.call('change', this, t);
84581           }
84582
84583           function removeMultikey(d3_event, d) {
84584             d3_event.preventDefault();
84585             d3_event.stopPropagation();
84586             var t = {};
84587
84588             if (_isMulti) {
84589               t[d.key] = undefined;
84590             } else if (_isSemi) {
84591               var arr = _multiData.map(function (md) {
84592                 return md.key === d.key ? null : md.key;
84593               }).filter(Boolean);
84594
84595               arr = utilArrayUniq(arr);
84596               t[field.key] = arr.length ? arr.join(';') : undefined;
84597             }
84598
84599             dispatch$1.call('change', this, t);
84600           }
84601
84602           function combo(selection) {
84603             _container = selection.selectAll('.form-field-input-wrap').data([0]);
84604             var type = _isMulti || _isSemi ? 'multicombo' : 'combo';
84605             _container = _container.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + type).merge(_container);
84606
84607             if (_isMulti || _isSemi) {
84608               _container = _container.selectAll('.chiplist').data([0]);
84609               var listClass = 'chiplist'; // Use a separate line for each value in the Destinations field
84610               // to mimic highway exit signs
84611
84612               if (field.key === 'destination') {
84613                 listClass += ' full-line-chips';
84614               }
84615
84616               _container = _container.enter().append('ul').attr('class', listClass).on('click', function () {
84617                 window.setTimeout(function () {
84618                   _input.node().focus();
84619                 }, 10);
84620               }).merge(_container);
84621               _inputWrap = _container.selectAll('.input-wrap').data([0]);
84622               _inputWrap = _inputWrap.enter().append('li').attr('class', 'input-wrap').merge(_inputWrap);
84623               _input = _inputWrap.selectAll('input').data([0]);
84624             } else {
84625               _input = _container.selectAll('input').data([0]);
84626             }
84627
84628             _input = _input.enter().append('input').attr('type', 'text').attr('id', field.domId).call(utilNoAuto).call(initCombo, selection).merge(_input);
84629
84630             if (_isNetwork) {
84631               var extent = combinedEntityExtent();
84632               var countryCode = extent && iso1A2Code(extent.center());
84633               _countryCode = countryCode && countryCode.toLowerCase();
84634             }
84635
84636             _input.on('change', change).on('blur', change);
84637
84638             _input.on('keydown.field', function (d3_event) {
84639               switch (d3_event.keyCode) {
84640                 case 13:
84641                   // ↩ Return
84642                   _input.node().blur(); // blurring also enters the value
84643
84644
84645                   d3_event.stopPropagation();
84646                   break;
84647               }
84648             });
84649
84650             if (_isMulti || _isSemi) {
84651               _combobox.on('accept', function () {
84652                 _input.node().blur();
84653
84654                 _input.node().focus();
84655               });
84656
84657               _input.on('focus', function () {
84658                 _container.classed('active', true);
84659               });
84660             }
84661           }
84662
84663           combo.tags = function (tags) {
84664             _tags = tags;
84665
84666             if (_isMulti || _isSemi) {
84667               _multiData = [];
84668               var maxLength;
84669
84670               if (_isMulti) {
84671                 // Build _multiData array containing keys already set..
84672                 for (var k in tags) {
84673                   if (field.key && k.indexOf(field.key) !== 0 || field.keys.indexOf(k) === -1) continue;
84674                   var v = tags[k];
84675                   if (!v || typeof v === 'string' && v.toLowerCase() === 'no') continue;
84676                   var suffix = field.key ? k.substring(field.key.length) : k;
84677
84678                   _multiData.push({
84679                     key: k,
84680                     value: displayValue(suffix),
84681                     isMixed: Array.isArray(v)
84682                   });
84683                 }
84684
84685                 if (field.key) {
84686                   // Set keys for form-field modified (needed for undo and reset buttons)..
84687                   field.keys = _multiData.map(function (d) {
84688                     return d.key;
84689                   }); // limit the input length so it fits after prepending the key prefix
84690
84691                   maxLength = context.maxCharsForTagKey() - utilUnicodeCharsCount(field.key);
84692                 } else {
84693                   maxLength = context.maxCharsForTagKey();
84694                 }
84695               } else if (_isSemi) {
84696                 var allValues = [];
84697                 var commonValues;
84698
84699                 if (Array.isArray(tags[field.key])) {
84700                   tags[field.key].forEach(function (tagVal) {
84701                     var thisVals = utilArrayUniq((tagVal || '').split(';')).filter(Boolean);
84702                     allValues = allValues.concat(thisVals);
84703
84704                     if (!commonValues) {
84705                       commonValues = thisVals;
84706                     } else {
84707                       commonValues = commonValues.filter(function (value) {
84708                         return thisVals.includes(value);
84709                       });
84710                     }
84711                   });
84712                   allValues = utilArrayUniq(allValues).filter(Boolean);
84713                 } else {
84714                   allValues = utilArrayUniq((tags[field.key] || '').split(';')).filter(Boolean);
84715                   commonValues = allValues;
84716                 }
84717
84718                 _multiData = allValues.map(function (v) {
84719                   return {
84720                     key: v,
84721                     value: displayValue(v),
84722                     isMixed: !commonValues.includes(v)
84723                   };
84724                 });
84725                 var currLength = utilUnicodeCharsCount(commonValues.join(';')); // limit the input length to the remaining available characters
84726
84727                 maxLength = context.maxCharsForTagValue() - currLength;
84728
84729                 if (currLength > 0) {
84730                   // account for the separator if a new value will be appended to existing
84731                   maxLength -= 1;
84732                 }
84733               } // a negative maxlength doesn't make sense
84734
84735
84736               maxLength = Math.max(0, maxLength);
84737               var allowDragAndDrop = _isSemi // only semiCombo values are ordered
84738               && !Array.isArray(tags[field.key]); // Exclude existing multikeys from combo options..
84739
84740               var available = objectDifference(_comboData, _multiData);
84741
84742               _combobox.data(available); // Hide 'Add' button if this field uses fixed set of
84743               // translateable _optstrings and they're all currently used,
84744               // or if the field is already at its character limit
84745
84746
84747               var hideAdd = _optstrings && !available.length || maxLength <= 0;
84748
84749               _container.selectAll('.chiplist .input-wrap').style('display', hideAdd ? 'none' : null); // Render chips
84750
84751
84752               var chips = _container.selectAll('.chip').data(_multiData);
84753
84754               chips.exit().remove();
84755               var enter = chips.enter().insert('li', '.input-wrap').attr('class', 'chip');
84756               enter.append('span');
84757               enter.append('a');
84758               chips = chips.merge(enter).order().classed('draggable', allowDragAndDrop).classed('mixed', function (d) {
84759                 return d.isMixed;
84760               }).attr('title', function (d) {
84761                 return d.isMixed ? _t('inspector.unshared_value_tooltip') : null;
84762               });
84763
84764               if (allowDragAndDrop) {
84765                 registerDragAndDrop(chips);
84766               }
84767
84768               chips.select('span').html(function (d) {
84769                 return d.value;
84770               });
84771               chips.select('a').attr('href', '#').on('click', removeMultikey).attr('class', 'remove').html('×');
84772             } else {
84773               var isMixed = Array.isArray(tags[field.key]);
84774               var mixedValues = isMixed && tags[field.key].map(function (val) {
84775                 return displayValue(val);
84776               }).filter(Boolean);
84777               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);
84778             }
84779           };
84780
84781           function registerDragAndDrop(selection) {
84782             // allow drag and drop re-ordering of chips
84783             var dragOrigin, targetIndex;
84784             selection.call(d3_drag().on('start', function (d3_event) {
84785               dragOrigin = {
84786                 x: d3_event.x,
84787                 y: d3_event.y
84788               };
84789               targetIndex = null;
84790             }).on('drag', function (d3_event) {
84791               var x = d3_event.x - dragOrigin.x,
84792                   y = d3_event.y - dragOrigin.y;
84793               if (!select(this).classed('dragging') && // don't display drag until dragging beyond a distance threshold
84794               Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return;
84795               var index = selection.nodes().indexOf(this);
84796               select(this).classed('dragging', true);
84797               targetIndex = null;
84798               var targetIndexOffsetTop = null;
84799               var draggedTagWidth = select(this).node().offsetWidth;
84800
84801               if (field.key === 'destination') {
84802                 // meaning tags are full width
84803                 _container.selectAll('.chip').style('transform', function (d2, index2) {
84804                   var node = select(this).node();
84805
84806                   if (index === index2) {
84807                     return 'translate(' + x + 'px, ' + y + 'px)'; // move the dragged tag up the order
84808                   } else if (index2 > index && d3_event.y > node.offsetTop) {
84809                     if (targetIndex === null || index2 > targetIndex) {
84810                       targetIndex = index2;
84811                     }
84812
84813                     return 'translateY(-100%)'; // move the dragged tag down the order
84814                   } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
84815                     if (targetIndex === null || index2 < targetIndex) {
84816                       targetIndex = index2;
84817                     }
84818
84819                     return 'translateY(100%)';
84820                   }
84821
84822                   return null;
84823                 });
84824               } else {
84825                 _container.selectAll('.chip').each(function (d2, index2) {
84826                   var node = select(this).node(); // check the cursor is in the bounding box
84827
84828                   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) {
84829                     targetIndex = index2;
84830                     targetIndexOffsetTop = node.offsetTop;
84831                   }
84832                 }).style('transform', function (d2, index2) {
84833                   var node = select(this).node();
84834
84835                   if (index === index2) {
84836                     return 'translate(' + x + 'px, ' + y + 'px)';
84837                   } // only translate tags in the same row
84838
84839
84840                   if (node.offsetTop === targetIndexOffsetTop) {
84841                     if (index2 < index && index2 >= targetIndex) {
84842                       return 'translateX(' + draggedTagWidth + 'px)';
84843                     } else if (index2 > index && index2 <= targetIndex) {
84844                       return 'translateX(-' + draggedTagWidth + 'px)';
84845                     }
84846                   }
84847
84848                   return null;
84849                 });
84850               }
84851             }).on('end', function () {
84852               if (!select(this).classed('dragging')) {
84853                 return;
84854               }
84855
84856               var index = selection.nodes().indexOf(this);
84857               select(this).classed('dragging', false);
84858
84859               _container.selectAll('.chip').style('transform', null);
84860
84861               if (typeof targetIndex === 'number') {
84862                 var element = _multiData[index];
84863
84864                 _multiData.splice(index, 1);
84865
84866                 _multiData.splice(targetIndex, 0, element);
84867
84868                 var t = {};
84869
84870                 if (_multiData.length) {
84871                   t[field.key] = _multiData.map(function (element) {
84872                     return element.key;
84873                   }).join(';');
84874                 } else {
84875                   t[field.key] = undefined;
84876                 }
84877
84878                 dispatch$1.call('change', this, t);
84879               }
84880
84881               dragOrigin = undefined;
84882               targetIndex = undefined;
84883             }));
84884           }
84885
84886           combo.focus = function () {
84887             _input.node().focus();
84888           };
84889
84890           combo.entityIDs = function (val) {
84891             if (!arguments.length) return _entityIDs;
84892             _entityIDs = val;
84893             return combo;
84894           };
84895
84896           function combinedEntityExtent() {
84897             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
84898           }
84899
84900           return utilRebind(combo, dispatch$1, 'on');
84901         }
84902
84903         function uiFieldText(field, context) {
84904           var dispatch$1 = dispatch('change');
84905           var input = select(null);
84906           var outlinkButton = select(null);
84907           var _entityIDs = [];
84908
84909           var _tags;
84910
84911           var _phoneFormats = {};
84912
84913           if (field.type === 'tel') {
84914             _mainFileFetcher.get('phone_formats').then(function (d) {
84915               _phoneFormats = d;
84916               updatePhonePlaceholder();
84917             })["catch"](function () {
84918               /* ignore */
84919             });
84920           }
84921
84922           function i(selection) {
84923             var entity = _entityIDs.length && context.hasEntity(_entityIDs[0]);
84924             var preset = entity && _mainPresetIndex.match(entity, context.graph());
84925             var isLocked = preset && preset.suggestion && field.id === 'brand';
84926             field.locked(isLocked);
84927             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
84928             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
84929             input = wrap.selectAll('input').data([0]);
84930             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);
84931             input.classed('disabled', !!isLocked).attr('readonly', isLocked || null).on('input', change(true)).on('blur', change()).on('change', change());
84932
84933             if (field.type === 'tel') {
84934               updatePhonePlaceholder();
84935             } else if (field.type === 'number') {
84936               var rtl = _mainLocalizer.textDirection() === 'rtl';
84937               input.attr('type', 'text');
84938               var inc = field.increment;
84939               var buttons = wrap.selectAll('.increment, .decrement').data(rtl ? [inc, -inc] : [-inc, inc]);
84940               buttons.enter().append('button').attr('class', function (d) {
84941                 var which = d > 0 ? 'increment' : 'decrement';
84942                 return 'form-field-button ' + which;
84943               }).merge(buttons).on('click', function (d3_event, d) {
84944                 d3_event.preventDefault();
84945                 var raw_vals = input.node().value || '0';
84946                 var vals = raw_vals.split(';');
84947                 vals = vals.map(function (v) {
84948                   var num = parseFloat(v.trim(), 10);
84949                   return isFinite(num) ? clamped(num + d) : v.trim();
84950                 });
84951                 input.node().value = vals.join(';');
84952                 change()();
84953               });
84954             } else if (field.type === 'identifier' && field.urlFormat && field.pattern) {
84955               input.attr('type', 'text');
84956               outlinkButton = wrap.selectAll('.foreign-id-permalink').data([0]);
84957               outlinkButton.enter().append('button').call(svgIcon('#iD-icon-out-link')).attr('class', 'form-field-button foreign-id-permalink').attr('title', function () {
84958                 var domainResults = /^https?:\/\/(.{1,}?)\//.exec(field.urlFormat);
84959
84960                 if (domainResults.length >= 2 && domainResults[1]) {
84961                   var domain = domainResults[1];
84962                   return _t('icons.view_on', {
84963                     domain: domain
84964                   });
84965                 }
84966
84967                 return '';
84968               }).on('click', function (d3_event) {
84969                 d3_event.preventDefault();
84970                 var value = validIdentifierValueForLink();
84971
84972                 if (value) {
84973                   var url = field.urlFormat.replace(/{value}/, encodeURIComponent(value));
84974                   window.open(url, '_blank');
84975                 }
84976               }).merge(outlinkButton);
84977             }
84978           }
84979
84980           function updatePhonePlaceholder() {
84981             if (input.empty() || !Object.keys(_phoneFormats).length) return;
84982             var extent = combinedEntityExtent();
84983             var countryCode = extent && iso1A2Code(extent.center());
84984
84985             var format = countryCode && _phoneFormats[countryCode.toLowerCase()];
84986
84987             if (format) input.attr('placeholder', format);
84988           }
84989
84990           function validIdentifierValueForLink() {
84991             if (field.type === 'identifier' && field.pattern) {
84992               var value = utilGetSetValue(input).trim().split(';')[0];
84993               return value && value.match(new RegExp(field.pattern));
84994             }
84995
84996             return null;
84997           } // clamp number to min/max
84998
84999
85000           function clamped(num) {
85001             if (field.minValue !== undefined) {
85002               num = Math.max(num, field.minValue);
85003             }
85004
85005             if (field.maxValue !== undefined) {
85006               num = Math.min(num, field.maxValue);
85007             }
85008
85009             return num;
85010           }
85011
85012           function change(onInput) {
85013             return function () {
85014               var t = {};
85015               var val = utilGetSetValue(input);
85016               if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
85017
85018               if (!val && Array.isArray(_tags[field.key])) return;
85019
85020               if (!onInput) {
85021                 if (field.type === 'number' && val) {
85022                   var vals = val.split(';');
85023                   vals = vals.map(function (v) {
85024                     var num = parseFloat(v.trim(), 10);
85025                     return isFinite(num) ? clamped(num) : v.trim();
85026                   });
85027                   val = vals.join(';');
85028                 }
85029
85030                 utilGetSetValue(input, val);
85031               }
85032
85033               t[field.key] = val || undefined;
85034               dispatch$1.call('change', this, t, onInput);
85035             };
85036           }
85037
85038           i.entityIDs = function (val) {
85039             if (!arguments.length) return _entityIDs;
85040             _entityIDs = val;
85041             return i;
85042           };
85043
85044           i.tags = function (tags) {
85045             _tags = tags;
85046             var isMixed = Array.isArray(tags[field.key]);
85047             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);
85048
85049             if (outlinkButton && !outlinkButton.empty()) {
85050               var disabled = !validIdentifierValueForLink();
85051               outlinkButton.classed('disabled', disabled);
85052             }
85053           };
85054
85055           i.focus = function () {
85056             var node = input.node();
85057             if (node) node.focus();
85058           };
85059
85060           function combinedEntityExtent() {
85061             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
85062           }
85063
85064           return utilRebind(i, dispatch$1, 'on');
85065         }
85066
85067         function uiFieldAccess(field, context) {
85068           var dispatch$1 = dispatch('change');
85069           var items = select(null);
85070
85071           var _tags;
85072
85073           function access(selection) {
85074             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
85075             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
85076             var list = wrap.selectAll('ul').data([0]);
85077             list = list.enter().append('ul').attr('class', 'rows').merge(list);
85078             items = list.selectAll('li').data(field.keys); // Enter
85079
85080             var enter = items.enter().append('li').attr('class', function (d) {
85081               return 'labeled-input preset-access-' + d;
85082             });
85083             enter.append('span').attr('class', 'label preset-label-access').attr('for', function (d) {
85084               return 'preset-input-access-' + d;
85085             }).html(function (d) {
85086               return field.t.html('types.' + d);
85087             });
85088             enter.append('div').attr('class', 'preset-input-access-wrap').append('input').attr('type', 'text').attr('class', function (d) {
85089               return 'preset-input-access preset-input-access-' + d;
85090             }).call(utilNoAuto).each(function (d) {
85091               select(this).call(uiCombobox(context, 'access-' + d).data(access.options(d)));
85092             }); // Update
85093
85094             items = items.merge(enter);
85095             wrap.selectAll('.preset-input-access').on('change', change).on('blur', change);
85096           }
85097
85098           function change(d3_event, d) {
85099             var tag = {};
85100             var value = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
85101
85102             if (!value && typeof _tags[d] !== 'string') return;
85103             tag[d] = value || undefined;
85104             dispatch$1.call('change', this, tag);
85105           }
85106
85107           access.options = function (type) {
85108             var options = ['no', 'permissive', 'private', 'permit', 'destination'];
85109
85110             if (type !== 'access') {
85111               options.unshift('yes');
85112               options.push('designated');
85113
85114               if (type === 'bicycle') {
85115                 options.push('dismount');
85116               }
85117             }
85118
85119             return options.map(function (option) {
85120               return {
85121                 title: field.t('options.' + option + '.description'),
85122                 value: option
85123               };
85124             });
85125           };
85126
85127           var placeholdersByHighway = {
85128             footway: {
85129               foot: 'designated',
85130               motor_vehicle: 'no'
85131             },
85132             steps: {
85133               foot: 'yes',
85134               motor_vehicle: 'no',
85135               bicycle: 'no',
85136               horse: 'no'
85137             },
85138             pedestrian: {
85139               foot: 'yes',
85140               motor_vehicle: 'no'
85141             },
85142             cycleway: {
85143               motor_vehicle: 'no',
85144               bicycle: 'designated'
85145             },
85146             bridleway: {
85147               motor_vehicle: 'no',
85148               horse: 'designated'
85149             },
85150             path: {
85151               foot: 'yes',
85152               motor_vehicle: 'no',
85153               bicycle: 'yes',
85154               horse: 'yes'
85155             },
85156             motorway: {
85157               foot: 'no',
85158               motor_vehicle: 'yes',
85159               bicycle: 'no',
85160               horse: 'no'
85161             },
85162             trunk: {
85163               motor_vehicle: 'yes'
85164             },
85165             primary: {
85166               foot: 'yes',
85167               motor_vehicle: 'yes',
85168               bicycle: 'yes',
85169               horse: 'yes'
85170             },
85171             secondary: {
85172               foot: 'yes',
85173               motor_vehicle: 'yes',
85174               bicycle: 'yes',
85175               horse: 'yes'
85176             },
85177             tertiary: {
85178               foot: 'yes',
85179               motor_vehicle: 'yes',
85180               bicycle: 'yes',
85181               horse: 'yes'
85182             },
85183             residential: {
85184               foot: 'yes',
85185               motor_vehicle: 'yes',
85186               bicycle: 'yes',
85187               horse: 'yes'
85188             },
85189             unclassified: {
85190               foot: 'yes',
85191               motor_vehicle: 'yes',
85192               bicycle: 'yes',
85193               horse: 'yes'
85194             },
85195             service: {
85196               foot: 'yes',
85197               motor_vehicle: 'yes',
85198               bicycle: 'yes',
85199               horse: 'yes'
85200             },
85201             motorway_link: {
85202               foot: 'no',
85203               motor_vehicle: 'yes',
85204               bicycle: 'no',
85205               horse: 'no'
85206             },
85207             trunk_link: {
85208               motor_vehicle: 'yes'
85209             },
85210             primary_link: {
85211               foot: 'yes',
85212               motor_vehicle: 'yes',
85213               bicycle: 'yes',
85214               horse: 'yes'
85215             },
85216             secondary_link: {
85217               foot: 'yes',
85218               motor_vehicle: 'yes',
85219               bicycle: 'yes',
85220               horse: 'yes'
85221             },
85222             tertiary_link: {
85223               foot: 'yes',
85224               motor_vehicle: 'yes',
85225               bicycle: 'yes',
85226               horse: 'yes'
85227             }
85228           };
85229
85230           access.tags = function (tags) {
85231             _tags = tags;
85232             utilGetSetValue(items.selectAll('.preset-input-access'), function (d) {
85233               return typeof tags[d] === 'string' ? tags[d] : '';
85234             }).classed('mixed', function (d) {
85235               return tags[d] && Array.isArray(tags[d]);
85236             }).attr('title', function (d) {
85237               return tags[d] && Array.isArray(tags[d]) && tags[d].filter(Boolean).join('\n');
85238             }).attr('placeholder', function (d) {
85239               if (tags[d] && Array.isArray(tags[d])) {
85240                 return _t('inspector.multiple_values');
85241               }
85242
85243               if (d === 'access') {
85244                 return 'yes';
85245               }
85246
85247               if (tags.access && typeof tags.access === 'string') {
85248                 return tags.access;
85249               }
85250
85251               if (tags.highway) {
85252                 if (typeof tags.highway === 'string') {
85253                   if (placeholdersByHighway[tags.highway] && placeholdersByHighway[tags.highway][d]) {
85254                     return placeholdersByHighway[tags.highway][d];
85255                   }
85256                 } else {
85257                   var impliedAccesses = tags.highway.filter(Boolean).map(function (highwayVal) {
85258                     return placeholdersByHighway[highwayVal] && placeholdersByHighway[highwayVal][d];
85259                   }).filter(Boolean);
85260
85261                   if (impliedAccesses.length === tags.highway.length && new Set(impliedAccesses).size === 1) {
85262                     // if all the highway values have the same implied access for this type then use that
85263                     return impliedAccesses[0];
85264                   }
85265                 }
85266               }
85267
85268               return field.placeholder();
85269             });
85270           };
85271
85272           access.focus = function () {
85273             items.selectAll('.preset-input-access').node().focus();
85274           };
85275
85276           return utilRebind(access, dispatch$1, 'on');
85277         }
85278
85279         function uiFieldAddress(field, context) {
85280           var dispatch$1 = dispatch('change');
85281
85282           var _selection = select(null);
85283
85284           var _wrap = select(null);
85285
85286           var addrField = _mainPresetIndex.field('address'); // needed for placeholder strings
85287
85288           var _entityIDs = [];
85289
85290           var _tags;
85291
85292           var _countryCode;
85293
85294           var _addressFormats = [{
85295             format: [['housenumber', 'street'], ['city', 'postcode']]
85296           }];
85297           _mainFileFetcher.get('address_formats').then(function (d) {
85298             _addressFormats = d;
85299
85300             if (!_selection.empty()) {
85301               _selection.call(address);
85302             }
85303           })["catch"](function () {
85304             /* ignore */
85305           });
85306
85307           function getNearStreets() {
85308             var extent = combinedEntityExtent();
85309             var l = extent.center();
85310             var box = geoExtent(l).padByMeters(200);
85311             var streets = context.history().intersects(box).filter(isAddressable).map(function (d) {
85312               var loc = context.projection([(extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2]);
85313               var choice = geoChooseEdge(context.graph().childNodes(d), loc, context.projection);
85314               return {
85315                 title: d.tags.name,
85316                 value: d.tags.name,
85317                 dist: choice.distance
85318               };
85319             }).sort(function (a, b) {
85320               return a.dist - b.dist;
85321             });
85322             return utilArrayUniqBy(streets, 'value');
85323
85324             function isAddressable(d) {
85325               return d.tags.highway && d.tags.name && d.type === 'way';
85326             }
85327           }
85328
85329           function getNearCities() {
85330             var extent = combinedEntityExtent();
85331             var l = extent.center();
85332             var box = geoExtent(l).padByMeters(200);
85333             var cities = context.history().intersects(box).filter(isAddressable).map(function (d) {
85334               return {
85335                 title: d.tags['addr:city'] || d.tags.name,
85336                 value: d.tags['addr:city'] || d.tags.name,
85337                 dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
85338               };
85339             }).sort(function (a, b) {
85340               return a.dist - b.dist;
85341             });
85342             return utilArrayUniqBy(cities, 'value');
85343
85344             function isAddressable(d) {
85345               if (d.tags.name) {
85346                 if (d.tags.admin_level === '8' && d.tags.boundary === 'administrative') return true;
85347                 if (d.tags.border_type === 'city') return true;
85348                 if (d.tags.place === 'city' || d.tags.place === 'town' || d.tags.place === 'village') return true;
85349               }
85350
85351               if (d.tags['addr:city']) return true;
85352               return false;
85353             }
85354           }
85355
85356           function getNearValues(key) {
85357             var extent = combinedEntityExtent();
85358             var l = extent.center();
85359             var box = geoExtent(l).padByMeters(200);
85360             var results = context.history().intersects(box).filter(function hasTag(d) {
85361               return _entityIDs.indexOf(d.id) === -1 && d.tags[key];
85362             }).map(function (d) {
85363               return {
85364                 title: d.tags[key],
85365                 value: d.tags[key],
85366                 dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
85367               };
85368             }).sort(function (a, b) {
85369               return a.dist - b.dist;
85370             });
85371             return utilArrayUniqBy(results, 'value');
85372           }
85373
85374           function updateForCountryCode() {
85375             if (!_countryCode) return;
85376             var addressFormat;
85377
85378             for (var i = 0; i < _addressFormats.length; i++) {
85379               var format = _addressFormats[i];
85380
85381               if (!format.countryCodes) {
85382                 addressFormat = format; // choose the default format, keep going
85383               } else if (format.countryCodes.indexOf(_countryCode) !== -1) {
85384                 addressFormat = format; // choose the country format, stop here
85385
85386                 break;
85387               }
85388             }
85389
85390             var dropdowns = addressFormat.dropdowns || ['city', 'county', 'country', 'district', 'hamlet', 'neighbourhood', 'place', 'postcode', 'province', 'quarter', 'state', 'street', 'subdistrict', 'suburb'];
85391             var widths = addressFormat.widths || {
85392               housenumber: 1 / 3,
85393               street: 2 / 3,
85394               city: 2 / 3,
85395               state: 1 / 4,
85396               postcode: 1 / 3
85397             };
85398
85399             function row(r) {
85400               // Normalize widths.
85401               var total = r.reduce(function (sum, key) {
85402                 return sum + (widths[key] || 0.5);
85403               }, 0);
85404               return r.map(function (key) {
85405                 return {
85406                   id: key,
85407                   width: (widths[key] || 0.5) / total
85408                 };
85409               });
85410             }
85411
85412             var rows = _wrap.selectAll('.addr-row').data(addressFormat.format, function (d) {
85413               return d.toString();
85414             });
85415
85416             rows.exit().remove();
85417             rows.enter().append('div').attr('class', 'addr-row').selectAll('input').data(row).enter().append('input').property('type', 'text').call(updatePlaceholder).attr('class', function (d) {
85418               return 'addr-' + d.id;
85419             }).call(utilNoAuto).each(addDropdown).style('width', function (d) {
85420               return d.width * 100 + '%';
85421             });
85422
85423             function addDropdown(d) {
85424               if (dropdowns.indexOf(d.id) === -1) return; // not a dropdown
85425
85426               var nearValues = d.id === 'street' ? getNearStreets : d.id === 'city' ? getNearCities : getNearValues;
85427               select(this).call(uiCombobox(context, 'address-' + d.id).minItems(1).caseSensitive(true).fetcher(function (value, callback) {
85428                 callback(nearValues('addr:' + d.id));
85429               }));
85430             }
85431
85432             _wrap.selectAll('input').on('blur', change()).on('change', change());
85433
85434             _wrap.selectAll('input:not(.combobox-input)').on('input', change(true));
85435
85436             if (_tags) updateTags(_tags);
85437           }
85438
85439           function address(selection) {
85440             _selection = selection;
85441             _wrap = selection.selectAll('.form-field-input-wrap').data([0]);
85442             _wrap = _wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(_wrap);
85443             var extent = combinedEntityExtent();
85444
85445             if (extent) {
85446               var countryCode;
85447
85448               if (context.inIntro()) {
85449                 // localize the address format for the walkthrough
85450                 countryCode = _t('intro.graph.countrycode');
85451               } else {
85452                 var center = extent.center();
85453                 countryCode = iso1A2Code(center);
85454               }
85455
85456               if (countryCode) {
85457                 _countryCode = countryCode.toLowerCase();
85458                 updateForCountryCode();
85459               }
85460             }
85461           }
85462
85463           function change(onInput) {
85464             return function () {
85465               var tags = {};
85466
85467               _wrap.selectAll('input').each(function (subfield) {
85468                 var key = field.key + ':' + subfield.id;
85469                 var value = this.value;
85470                 if (!onInput) value = context.cleanTagValue(value); // don't override multiple values with blank string
85471
85472                 if (Array.isArray(_tags[key]) && !value) return;
85473                 tags[key] = value || undefined;
85474               });
85475
85476               dispatch$1.call('change', this, tags, onInput);
85477             };
85478           }
85479
85480           function updatePlaceholder(inputSelection) {
85481             return inputSelection.attr('placeholder', function (subfield) {
85482               if (_tags && Array.isArray(_tags[field.key + ':' + subfield.id])) {
85483                 return _t('inspector.multiple_values');
85484               }
85485
85486               if (_countryCode) {
85487                 var localkey = subfield.id + '!' + _countryCode;
85488                 var tkey = addrField.strings.placeholders[localkey] ? localkey : subfield.id;
85489                 return addrField.t('placeholders.' + tkey);
85490               }
85491             });
85492           }
85493
85494           function updateTags(tags) {
85495             utilGetSetValue(_wrap.selectAll('input'), function (subfield) {
85496               var val = tags[field.key + ':' + subfield.id];
85497               return typeof val === 'string' ? val : '';
85498             }).attr('title', function (subfield) {
85499               var val = tags[field.key + ':' + subfield.id];
85500               return val && Array.isArray(val) && val.filter(Boolean).join('\n');
85501             }).classed('mixed', function (subfield) {
85502               return Array.isArray(tags[field.key + ':' + subfield.id]);
85503             }).call(updatePlaceholder);
85504           }
85505
85506           function combinedEntityExtent() {
85507             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
85508           }
85509
85510           address.entityIDs = function (val) {
85511             if (!arguments.length) return _entityIDs;
85512             _entityIDs = val;
85513             return address;
85514           };
85515
85516           address.tags = function (tags) {
85517             _tags = tags;
85518             updateTags(tags);
85519           };
85520
85521           address.focus = function () {
85522             var node = _wrap.selectAll('input').node();
85523
85524             if (node) node.focus();
85525           };
85526
85527           return utilRebind(address, dispatch$1, 'on');
85528         }
85529
85530         function uiFieldCycleway(field, context) {
85531           var dispatch$1 = dispatch('change');
85532           var items = select(null);
85533           var wrap = select(null);
85534
85535           var _tags;
85536
85537           function cycleway(selection) {
85538             function stripcolon(s) {
85539               return s.replace(':', '');
85540             }
85541
85542             wrap = selection.selectAll('.form-field-input-wrap').data([0]);
85543             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
85544             var div = wrap.selectAll('ul').data([0]);
85545             div = div.enter().append('ul').attr('class', 'rows').merge(div);
85546             var keys = ['cycleway:left', 'cycleway:right'];
85547             items = div.selectAll('li').data(keys);
85548             var enter = items.enter().append('li').attr('class', function (d) {
85549               return 'labeled-input preset-cycleway-' + stripcolon(d);
85550             });
85551             enter.append('span').attr('class', 'label preset-label-cycleway').attr('for', function (d) {
85552               return 'preset-input-cycleway-' + stripcolon(d);
85553             }).html(function (d) {
85554               return field.t.html('types.' + d);
85555             });
85556             enter.append('div').attr('class', 'preset-input-cycleway-wrap').append('input').attr('type', 'text').attr('class', function (d) {
85557               return 'preset-input-cycleway preset-input-' + stripcolon(d);
85558             }).call(utilNoAuto).each(function (d) {
85559               select(this).call(uiCombobox(context, 'cycleway-' + stripcolon(d)).data(cycleway.options(d)));
85560             });
85561             items = items.merge(enter); // Update
85562
85563             wrap.selectAll('.preset-input-cycleway').on('change', change).on('blur', change);
85564           }
85565
85566           function change(d3_event, key) {
85567             var newValue = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
85568
85569             if (!newValue && (Array.isArray(_tags.cycleway) || Array.isArray(_tags[key]))) return;
85570
85571             if (newValue === 'none' || newValue === '') {
85572               newValue = undefined;
85573             }
85574
85575             var otherKey = key === 'cycleway:left' ? 'cycleway:right' : 'cycleway:left';
85576             var otherValue = typeof _tags.cycleway === 'string' ? _tags.cycleway : _tags[otherKey];
85577
85578             if (otherValue && Array.isArray(otherValue)) {
85579               // we must always have an explicit value for comparison
85580               otherValue = otherValue[0];
85581             }
85582
85583             if (otherValue === 'none' || otherValue === '') {
85584               otherValue = undefined;
85585             }
85586
85587             var tag = {}; // If the left and right tags match, use the cycleway tag to tag both
85588             // sides the same way
85589
85590             if (newValue === otherValue) {
85591               tag = {
85592                 cycleway: newValue,
85593                 'cycleway:left': undefined,
85594                 'cycleway:right': undefined
85595               };
85596             } else {
85597               // Always set both left and right as changing one can affect the other
85598               tag = {
85599                 cycleway: undefined
85600               };
85601               tag[key] = newValue;
85602               tag[otherKey] = otherValue;
85603             }
85604
85605             dispatch$1.call('change', this, tag);
85606           }
85607
85608           cycleway.options = function () {
85609             return Object.keys(field.strings.options).map(function (option) {
85610               return {
85611                 title: field.t('options.' + option + '.description'),
85612                 value: option
85613               };
85614             });
85615           };
85616
85617           cycleway.tags = function (tags) {
85618             _tags = tags; // If cycleway is set, use that instead of individual values
85619
85620             var commonValue = typeof tags.cycleway === 'string' && tags.cycleway;
85621             utilGetSetValue(items.selectAll('.preset-input-cycleway'), function (d) {
85622               if (commonValue) return commonValue;
85623               return !tags.cycleway && typeof tags[d] === 'string' ? tags[d] : '';
85624             }).attr('title', function (d) {
85625               if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
85626                 var vals = [];
85627
85628                 if (Array.isArray(tags.cycleway)) {
85629                   vals = vals.concat(tags.cycleway);
85630                 }
85631
85632                 if (Array.isArray(tags[d])) {
85633                   vals = vals.concat(tags[d]);
85634                 }
85635
85636                 return vals.filter(Boolean).join('\n');
85637               }
85638
85639               return null;
85640             }).attr('placeholder', function (d) {
85641               if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
85642                 return _t('inspector.multiple_values');
85643               }
85644
85645               return field.placeholder();
85646             }).classed('mixed', function (d) {
85647               return Array.isArray(tags.cycleway) || Array.isArray(tags[d]);
85648             });
85649           };
85650
85651           cycleway.focus = function () {
85652             var node = wrap.selectAll('input').node();
85653             if (node) node.focus();
85654           };
85655
85656           return utilRebind(cycleway, dispatch$1, 'on');
85657         }
85658
85659         function uiFieldLanes(field, context) {
85660           var dispatch$1 = dispatch('change');
85661           var LANE_WIDTH = 40;
85662           var LANE_HEIGHT = 200;
85663           var _entityIDs = [];
85664
85665           function lanes(selection) {
85666             var lanesData = context.entity(_entityIDs[0]).lanes();
85667
85668             if (!context.container().select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode) {
85669               selection.call(lanes.off);
85670               return;
85671             }
85672
85673             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
85674             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
85675             var surface = wrap.selectAll('.surface').data([0]);
85676             var d = utilGetDimensions(wrap);
85677             var freeSpace = d[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
85678             surface = surface.enter().append('svg').attr('width', d[0]).attr('height', 300).attr('class', 'surface').merge(surface);
85679             var lanesSelection = surface.selectAll('.lanes').data([0]);
85680             lanesSelection = lanesSelection.enter().append('g').attr('class', 'lanes').merge(lanesSelection);
85681             lanesSelection.attr('transform', function () {
85682               return 'translate(' + freeSpace / 2 + ', 0)';
85683             });
85684             var lane = lanesSelection.selectAll('.lane').data(lanesData.lanes);
85685             lane.exit().remove();
85686             var enter = lane.enter().append('g').attr('class', 'lane');
85687             enter.append('g').append('rect').attr('y', 50).attr('width', LANE_WIDTH).attr('height', LANE_HEIGHT);
85688             enter.append('g').attr('class', 'forward').append('text').attr('y', 40).attr('x', 14).html('▲');
85689             enter.append('g').attr('class', 'bothways').append('text').attr('y', 40).attr('x', 14).html('▲▼');
85690             enter.append('g').attr('class', 'backward').append('text').attr('y', 40).attr('x', 14).html('▼');
85691             lane = lane.merge(enter);
85692             lane.attr('transform', function (d) {
85693               return 'translate(' + LANE_WIDTH * d.index * 1.5 + ', 0)';
85694             });
85695             lane.select('.forward').style('visibility', function (d) {
85696               return d.direction === 'forward' ? 'visible' : 'hidden';
85697             });
85698             lane.select('.bothways').style('visibility', function (d) {
85699               return d.direction === 'bothways' ? 'visible' : 'hidden';
85700             });
85701             lane.select('.backward').style('visibility', function (d) {
85702               return d.direction === 'backward' ? 'visible' : 'hidden';
85703             });
85704           }
85705
85706           lanes.entityIDs = function (val) {
85707             _entityIDs = val;
85708           };
85709
85710           lanes.tags = function () {};
85711
85712           lanes.focus = function () {};
85713
85714           lanes.off = function () {};
85715
85716           return utilRebind(lanes, dispatch$1, 'on');
85717         }
85718         uiFieldLanes.supportsMultiselection = false;
85719
85720         var _languagesArray = [];
85721         function uiFieldLocalized(field, context) {
85722           var dispatch$1 = dispatch('change', 'input');
85723           var wikipedia = services.wikipedia;
85724           var input = select(null);
85725           var localizedInputs = select(null);
85726
85727           var _countryCode;
85728
85729           var _tags; // A concern here in switching to async data means that _languagesArray will not
85730           // be available the first time through, so things like the fetchers and
85731           // the language() function will not work immediately.
85732
85733
85734           _mainFileFetcher.get('languages').then(loadLanguagesArray)["catch"](function () {
85735             /* ignore */
85736           });
85737           var _territoryLanguages = {};
85738           _mainFileFetcher.get('territory_languages').then(function (d) {
85739             _territoryLanguages = d;
85740           })["catch"](function () {
85741             /* ignore */
85742           });
85743           var allSuggestions = _mainPresetIndex.collection.filter(function (p) {
85744             return p.suggestion === true;
85745           }); // reuse these combos
85746
85747           var langCombo = uiCombobox(context, 'localized-lang').fetcher(fetchLanguages).minItems(0);
85748           var brandCombo = uiCombobox(context, 'localized-brand').canAutocomplete(false).minItems(1);
85749
85750           var _selection = select(null);
85751
85752           var _multilingual = [];
85753
85754           var _buttonTip = uiTooltip().title(_t.html('translate.translate')).placement('left');
85755
85756           var _wikiTitles;
85757
85758           var _entityIDs = [];
85759
85760           function loadLanguagesArray(dataLanguages) {
85761             if (_languagesArray.length !== 0) return; // some conversion is needed to ensure correct OSM tags are used
85762
85763             var replacements = {
85764               sr: 'sr-Cyrl',
85765               // in OSM, `sr` implies Cyrillic
85766               'sr-Cyrl': false // `sr-Cyrl` isn't used in OSM
85767
85768             };
85769
85770             for (var code in dataLanguages) {
85771               if (replacements[code] === false) continue;
85772               var metaCode = code;
85773               if (replacements[code]) metaCode = replacements[code];
85774
85775               _languagesArray.push({
85776                 localName: _mainLocalizer.languageName(metaCode, {
85777                   localOnly: true
85778                 }),
85779                 nativeName: dataLanguages[metaCode].nativeName,
85780                 code: code,
85781                 label: _mainLocalizer.languageName(metaCode)
85782               });
85783             }
85784           }
85785
85786           function calcLocked() {
85787             // only lock the Name field
85788             var isLocked = field.id === 'name' && _entityIDs.length && // lock the field if any feature needs it
85789             _entityIDs.some(function (entityID) {
85790               var entity = context.graph().hasEntity(entityID);
85791               if (!entity) return false;
85792
85793               var original = context.graph().base().entities[_entityIDs[0]];
85794
85795               var hasOriginalName = original && entity.tags.name && entity.tags.name === original.tags.name; // if the name was already edited manually then allow further editing
85796
85797               if (!hasOriginalName) return false; // features linked to Wikidata are likely important and should be protected
85798
85799               if (entity.tags.wikidata) return true; // assume the name has already been confirmed if its source has been researched
85800
85801               if (entity.tags['name:etymology:wikidata']) return true;
85802               var preset = _mainPresetIndex.match(entity, context.graph());
85803               var isSuggestion = preset && preset.suggestion;
85804               var showsBrand = preset && preset.originalFields.filter(function (d) {
85805                 return d.id === 'brand';
85806               }).length; // protect standardized brand names
85807
85808               return isSuggestion && !showsBrand;
85809             });
85810
85811             field.locked(isLocked);
85812           } // update _multilingual, maintaining the existing order
85813
85814
85815           function calcMultilingual(tags) {
85816             var existingLangsOrdered = _multilingual.map(function (item) {
85817               return item.lang;
85818             });
85819
85820             var existingLangs = new Set(existingLangsOrdered.filter(Boolean));
85821
85822             for (var k in tags) {
85823               var m = k.match(/^(.*):([a-zA-Z_-]+)$/);
85824
85825               if (m && m[1] === field.key && m[2]) {
85826                 var item = {
85827                   lang: m[2],
85828                   value: tags[k]
85829                 };
85830
85831                 if (existingLangs.has(item.lang)) {
85832                   // update the value
85833                   _multilingual[existingLangsOrdered.indexOf(item.lang)].value = item.value;
85834                   existingLangs["delete"](item.lang);
85835                 } else {
85836                   _multilingual.push(item);
85837                 }
85838               }
85839             }
85840
85841             _multilingual = _multilingual.filter(function (item) {
85842               return !item.lang || !existingLangs.has(item.lang);
85843             });
85844           }
85845
85846           function localized(selection) {
85847             _selection = selection;
85848             calcLocked();
85849             var isLocked = field.locked();
85850             var singularEntity = _entityIDs.length === 1 && context.hasEntity(_entityIDs[0]);
85851             var preset = singularEntity && _mainPresetIndex.match(singularEntity, context.graph());
85852             var wrap = selection.selectAll('.form-field-input-wrap').data([0]); // enter/update
85853
85854             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
85855             input = wrap.selectAll('.localized-main').data([0]); // enter/update
85856
85857             input = input.enter().append('input').attr('type', 'text').attr('id', field.domId).attr('class', 'localized-main').call(utilNoAuto).merge(input);
85858
85859             if (preset && field.id === 'name') {
85860               var pTag = preset.id.split('/', 2);
85861               var pKey = pTag[0];
85862               var pValue = pTag[1];
85863
85864               if (!preset.suggestion) {
85865                 // Not a suggestion preset - Add a suggestions dropdown if it makes sense to.
85866                 // This code attempts to determine if the matched preset is the
85867                 // kind of preset that even can benefit from name suggestions..
85868                 // - true = shops, cafes, hotels, etc. (also generic and fallback presets)
85869                 // - false = churches, parks, hospitals, etc. (things not in the index)
85870                 var isFallback = preset.isFallback();
85871                 var goodSuggestions = allSuggestions.filter(function (s) {
85872                   if (isFallback) return true;
85873                   var sTag = s.id.split('/', 2);
85874                   var sKey = sTag[0];
85875                   var sValue = sTag[1];
85876                   return pKey === sKey && (!pValue || pValue === sValue);
85877                 }); // Show the suggestions.. If the user picks one, change the tags..
85878
85879                 if (allSuggestions.length && goodSuggestions.length) {
85880                   input.on('blur.localized', checkBrandOnBlur).call(brandCombo.fetcher(fetchBrandNames(preset, allSuggestions)).on('accept', acceptBrand).on('cancel', cancelBrand));
85881                 }
85882               }
85883             }
85884
85885             input.classed('disabled', !!isLocked).attr('readonly', isLocked || null).on('input', change(true)).on('blur', change()).on('change', change());
85886             var translateButton = wrap.selectAll('.localized-add').data([0]);
85887             translateButton = translateButton.enter().append('button').attr('class', 'localized-add form-field-button').call(svgIcon('#iD-icon-plus')).merge(translateButton);
85888             translateButton.classed('disabled', !!isLocked).call(isLocked ? _buttonTip.destroy : _buttonTip).on('click', addNew);
85889
85890             if (_tags && !_multilingual.length) {
85891               calcMultilingual(_tags);
85892             }
85893
85894             localizedInputs = selection.selectAll('.localized-multilingual').data([0]);
85895             localizedInputs = localizedInputs.enter().append('div').attr('class', 'localized-multilingual').merge(localizedInputs);
85896             localizedInputs.call(renderMultilingual);
85897             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.
85898             // (This can happen if the user actives the combo, arrows down, and then clicks off to blur)
85899             // So compare the current field value against the suggestions one last time.
85900
85901             function checkBrandOnBlur() {
85902               var latest = _entityIDs.length === 1 && context.hasEntity(_entityIDs[0]);
85903               if (!latest) return; // deleting the entity blurred the field?
85904
85905               var preset = _mainPresetIndex.match(latest, context.graph());
85906               if (preset && preset.suggestion) return; // already accepted
85907
85908               var name = utilGetSetValue(input).trim();
85909               var matched = allSuggestions.filter(function (s) {
85910                 return name === s.name();
85911               });
85912
85913               if (matched.length === 1) {
85914                 acceptBrand({
85915                   suggestion: matched[0]
85916                 });
85917               } else {
85918                 cancelBrand();
85919               }
85920             }
85921
85922             function acceptBrand(d) {
85923               var entity = _entityIDs.length === 1 && context.hasEntity(_entityIDs[0]);
85924
85925               if (!d || !entity) {
85926                 cancelBrand();
85927                 return;
85928               }
85929
85930               var tags = entity.tags;
85931               var geometry = entity.geometry(context.graph());
85932               var removed = preset.unsetTags(tags, geometry);
85933
85934               for (var k in tags) {
85935                 tags[k] = removed[k]; // set removed tags to `undefined`
85936               }
85937
85938               tags = d.suggestion.setTags(tags, geometry);
85939               utilGetSetValue(input, tags.name);
85940               dispatch$1.call('change', this, tags);
85941             } // user hit escape
85942
85943
85944             function cancelBrand() {
85945               var name = utilGetSetValue(input);
85946               dispatch$1.call('change', this, {
85947                 name: name
85948               });
85949             }
85950
85951             function fetchBrandNames(preset, suggestions) {
85952               var pTag = preset.id.split('/', 2);
85953               var pKey = pTag[0];
85954               var pValue = pTag[1];
85955               return function (value, callback) {
85956                 var results = [];
85957
85958                 if (value && value.length > 2) {
85959                   for (var i = 0; i < suggestions.length; i++) {
85960                     var s = suggestions[i]; // don't suggest brands from incompatible countries
85961
85962                     if (_countryCode && s.countryCodes && s.countryCodes.indexOf(_countryCode) === -1) continue;
85963                     var sTag = s.id.split('/', 2);
85964                     var sKey = sTag[0];
85965                     var sValue = sTag[1];
85966                     var subtitle = s.subtitle();
85967                     var name = s.name();
85968                     if (subtitle) name += ' – ' + subtitle;
85969                     var dist = utilEditDistance(value, name.substring(0, value.length));
85970                     var matchesPreset = pKey === sKey && (!pValue || pValue === sValue);
85971
85972                     if (dist < 1 || matchesPreset && dist < 3) {
85973                       var obj = {
85974                         value: s.name(),
85975                         title: name,
85976                         display: s.nameLabel() + (subtitle ? ' – ' + s.subtitleLabel() : ''),
85977                         suggestion: s,
85978                         dist: dist + (matchesPreset ? 0 : 1) // penalize if not matched preset
85979
85980                       };
85981                       results.push(obj);
85982                     }
85983                   }
85984
85985                   results.sort(function (a, b) {
85986                     return a.dist - b.dist;
85987                   });
85988                 }
85989
85990                 results = results.slice(0, 10);
85991                 callback(results);
85992               };
85993             }
85994
85995             function addNew(d3_event) {
85996               d3_event.preventDefault();
85997               if (field.locked()) return;
85998               var defaultLang = _mainLocalizer.languageCode().toLowerCase();
85999
86000               var langExists = _multilingual.find(function (datum) {
86001                 return datum.lang === defaultLang;
86002               });
86003
86004               var isLangEn = defaultLang.indexOf('en') > -1;
86005
86006               if (isLangEn || langExists) {
86007                 defaultLang = '';
86008                 langExists = _multilingual.find(function (datum) {
86009                   return datum.lang === defaultLang;
86010                 });
86011               }
86012
86013               if (!langExists) {
86014                 // prepend the value so it appears at the top
86015                 _multilingual.unshift({
86016                   lang: defaultLang,
86017                   value: ''
86018                 });
86019
86020                 localizedInputs.call(renderMultilingual);
86021               }
86022             }
86023
86024             function change(onInput) {
86025               return function (d3_event) {
86026                 if (field.locked()) {
86027                   d3_event.preventDefault();
86028                   return;
86029                 }
86030
86031                 var val = utilGetSetValue(select(this));
86032                 if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
86033
86034                 if (!val && Array.isArray(_tags[field.key])) return;
86035                 var t = {};
86036                 t[field.key] = val || undefined;
86037                 dispatch$1.call('change', this, t, onInput);
86038               };
86039             }
86040           }
86041
86042           function key(lang) {
86043             return field.key + ':' + lang;
86044           }
86045
86046           function changeLang(d3_event, d) {
86047             var tags = {}; // make sure unrecognized suffixes are lowercase - #7156
86048
86049             var lang = utilGetSetValue(select(this)).toLowerCase();
86050
86051             var language = _languagesArray.find(function (d) {
86052               return d.label.toLowerCase() === lang || d.localName && d.localName.toLowerCase() === lang || d.nativeName && d.nativeName.toLowerCase() === lang;
86053             });
86054
86055             if (language) lang = language.code;
86056
86057             if (d.lang && d.lang !== lang) {
86058               tags[key(d.lang)] = undefined;
86059             }
86060
86061             var newKey = lang && context.cleanTagKey(key(lang));
86062             var value = utilGetSetValue(select(this.parentNode).selectAll('.localized-value'));
86063
86064             if (newKey && value) {
86065               tags[newKey] = value;
86066             } else if (newKey && _wikiTitles && _wikiTitles[d.lang]) {
86067               tags[newKey] = _wikiTitles[d.lang];
86068             }
86069
86070             d.lang = lang;
86071             dispatch$1.call('change', this, tags);
86072           }
86073
86074           function changeValue(d3_event, d) {
86075             if (!d.lang) return;
86076             var value = context.cleanTagValue(utilGetSetValue(select(this))) || undefined; // don't override multiple values with blank string
86077
86078             if (!value && Array.isArray(d.value)) return;
86079             var t = {};
86080             t[key(d.lang)] = value;
86081             d.value = value;
86082             dispatch$1.call('change', this, t);
86083           }
86084
86085           function fetchLanguages(value, cb) {
86086             var v = value.toLowerCase(); // show the user's language first
86087
86088             var langCodes = [_mainLocalizer.localeCode(), _mainLocalizer.languageCode()];
86089
86090             if (_countryCode && _territoryLanguages[_countryCode]) {
86091               langCodes = langCodes.concat(_territoryLanguages[_countryCode]);
86092             }
86093
86094             var langItems = [];
86095             langCodes.forEach(function (code) {
86096               var langItem = _languagesArray.find(function (item) {
86097                 return item.code === code;
86098               });
86099
86100               if (langItem) langItems.push(langItem);
86101             });
86102             langItems = utilArrayUniq(langItems.concat(_languagesArray));
86103             cb(langItems.filter(function (d) {
86104               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;
86105             }).map(function (d) {
86106               return {
86107                 value: d.label
86108               };
86109             }));
86110           }
86111
86112           function renderMultilingual(selection) {
86113             var entries = selection.selectAll('div.entry').data(_multilingual, function (d) {
86114               return d.lang;
86115             });
86116             entries.exit().style('top', '0').style('max-height', '240px').transition().duration(200).style('opacity', '0').style('max-height', '0px').remove();
86117             var entriesEnter = entries.enter().append('div').attr('class', 'entry').each(function (_, index) {
86118               var wrap = select(this);
86119               var domId = utilUniqueDomId(index);
86120               var label = wrap.append('label').attr('class', 'field-label').attr('for', domId);
86121               var text = label.append('span').attr('class', 'label-text');
86122               text.append('span').attr('class', 'label-textvalue').html(_t.html('translate.localized_translation_label'));
86123               text.append('span').attr('class', 'label-textannotation');
86124               label.append('button').attr('class', 'remove-icon-multilingual').on('click', function (d3_event, d) {
86125                 if (field.locked()) return;
86126                 d3_event.preventDefault();
86127
86128                 if (!d.lang || !d.value) {
86129                   _multilingual.splice(index, 1);
86130
86131                   renderMultilingual(selection);
86132                 } else {
86133                   // remove from entity tags
86134                   var t = {};
86135                   t[key(d.lang)] = undefined;
86136                   dispatch$1.call('change', this, t);
86137                 }
86138               }).call(svgIcon('#iD-operation-delete'));
86139               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);
86140               wrap.append('input').attr('type', 'text').attr('class', 'localized-value').on('blur', changeValue).on('change', changeValue);
86141             });
86142             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 () {
86143               select(this).style('max-height', '').style('overflow', 'visible');
86144             });
86145             entries = entries.merge(entriesEnter);
86146             entries.order();
86147             entries.classed('present', function (d) {
86148               return d.lang && d.value;
86149             });
86150             utilGetSetValue(entries.select('.localized-lang'), function (d) {
86151               return _mainLocalizer.languageName(d.lang);
86152             });
86153             utilGetSetValue(entries.select('.localized-value'), function (d) {
86154               return typeof d.value === 'string' ? d.value : '';
86155             }).attr('title', function (d) {
86156               return Array.isArray(d.value) ? d.value.filter(Boolean).join('\n') : null;
86157             }).attr('placeholder', function (d) {
86158               return Array.isArray(d.value) ? _t('inspector.multiple_values') : _t('translate.localized_translation_name');
86159             }).classed('mixed', function (d) {
86160               return Array.isArray(d.value);
86161             });
86162           }
86163
86164           localized.tags = function (tags) {
86165             _tags = tags; // Fetch translations from wikipedia
86166
86167             if (typeof tags.wikipedia === 'string' && !_wikiTitles) {
86168               _wikiTitles = {};
86169               var wm = tags.wikipedia.match(/([^:]+):(.+)/);
86170
86171               if (wm && wm[0] && wm[1]) {
86172                 wikipedia.translations(wm[1], wm[2], function (err, d) {
86173                   if (err || !d) return;
86174                   _wikiTitles = d;
86175                 });
86176               }
86177             }
86178
86179             var isMixed = Array.isArray(tags[field.key]);
86180             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);
86181             calcMultilingual(tags);
86182
86183             _selection.call(localized);
86184           };
86185
86186           localized.focus = function () {
86187             input.node().focus();
86188           };
86189
86190           localized.entityIDs = function (val) {
86191             if (!arguments.length) return _entityIDs;
86192             _entityIDs = val;
86193             _multilingual = [];
86194             loadCountryCode();
86195             return localized;
86196           };
86197
86198           function loadCountryCode() {
86199             var extent = combinedEntityExtent();
86200             var countryCode = extent && iso1A2Code(extent.center());
86201             _countryCode = countryCode && countryCode.toLowerCase();
86202           }
86203
86204           function combinedEntityExtent() {
86205             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
86206           }
86207
86208           return utilRebind(localized, dispatch$1, 'on');
86209         }
86210
86211         function uiFieldMaxspeed(field, context) {
86212           var dispatch$1 = dispatch('change');
86213           var unitInput = select(null);
86214           var input = select(null);
86215           var _entityIDs = [];
86216
86217           var _tags;
86218
86219           var _isImperial;
86220
86221           var speedCombo = uiCombobox(context, 'maxspeed');
86222           var unitCombo = uiCombobox(context, 'maxspeed-unit').data(['km/h', 'mph'].map(comboValues));
86223           var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120];
86224           var imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
86225
86226           function maxspeed(selection) {
86227             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
86228             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
86229             input = wrap.selectAll('input.maxspeed-number').data([0]);
86230             input = input.enter().append('input').attr('type', 'text').attr('class', 'maxspeed-number').attr('id', field.domId).call(utilNoAuto).call(speedCombo).merge(input);
86231             input.on('change', change).on('blur', change);
86232             var loc = combinedEntityExtent().center();
86233             _isImperial = roadSpeedUnit(loc) === 'mph';
86234             unitInput = wrap.selectAll('input.maxspeed-unit').data([0]);
86235             unitInput = unitInput.enter().append('input').attr('type', 'text').attr('class', 'maxspeed-unit').call(unitCombo).merge(unitInput);
86236             unitInput.on('blur', changeUnits).on('change', changeUnits);
86237
86238             function changeUnits() {
86239               _isImperial = utilGetSetValue(unitInput) === 'mph';
86240               utilGetSetValue(unitInput, _isImperial ? 'mph' : 'km/h');
86241               setUnitSuggestions();
86242               change();
86243             }
86244           }
86245
86246           function setUnitSuggestions() {
86247             speedCombo.data((_isImperial ? imperialValues : metricValues).map(comboValues));
86248             utilGetSetValue(unitInput, _isImperial ? 'mph' : 'km/h');
86249           }
86250
86251           function comboValues(d) {
86252             return {
86253               value: d.toString(),
86254               title: d.toString()
86255             };
86256           }
86257
86258           function change() {
86259             var tag = {};
86260             var value = utilGetSetValue(input).trim(); // don't override multiple values with blank string
86261
86262             if (!value && Array.isArray(_tags[field.key])) return;
86263
86264             if (!value) {
86265               tag[field.key] = undefined;
86266             } else if (isNaN(value) || !_isImperial) {
86267               tag[field.key] = context.cleanTagValue(value);
86268             } else {
86269               tag[field.key] = context.cleanTagValue(value + ' mph');
86270             }
86271
86272             dispatch$1.call('change', this, tag);
86273           }
86274
86275           maxspeed.tags = function (tags) {
86276             _tags = tags;
86277             var value = tags[field.key];
86278             var isMixed = Array.isArray(value);
86279
86280             if (!isMixed) {
86281               if (value && value.indexOf('mph') >= 0) {
86282                 value = parseInt(value, 10).toString();
86283                 _isImperial = true;
86284               } else if (value) {
86285                 _isImperial = false;
86286               }
86287             }
86288
86289             setUnitSuggestions();
86290             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);
86291           };
86292
86293           maxspeed.focus = function () {
86294             input.node().focus();
86295           };
86296
86297           maxspeed.entityIDs = function (val) {
86298             _entityIDs = val;
86299           };
86300
86301           function combinedEntityExtent() {
86302             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
86303           }
86304
86305           return utilRebind(maxspeed, dispatch$1, 'on');
86306         }
86307
86308         function uiFieldRadio(field, context) {
86309           var dispatch$1 = dispatch('change');
86310           var placeholder = select(null);
86311           var wrap = select(null);
86312           var labels = select(null);
86313           var radios = select(null);
86314           var radioData = (field.options || field.strings && field.strings.options && Object.keys(field.strings.options) || field.keys).slice(); // shallow copy
86315
86316           var typeField;
86317           var layerField;
86318           var _oldType = {};
86319           var _entityIDs = [];
86320
86321           function selectedKey() {
86322             var node = wrap.selectAll('.form-field-input-radio label.active input');
86323             return !node.empty() && node.datum();
86324           }
86325
86326           function radio(selection) {
86327             selection.classed('preset-radio', true);
86328             wrap = selection.selectAll('.form-field-input-wrap').data([0]);
86329             var enter = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-radio');
86330             enter.append('span').attr('class', 'placeholder');
86331             wrap = wrap.merge(enter);
86332             placeholder = wrap.selectAll('.placeholder');
86333             labels = wrap.selectAll('label').data(radioData);
86334             enter = labels.enter().append('label');
86335             enter.append('input').attr('type', 'radio').attr('name', field.id).attr('value', function (d) {
86336               return field.t('options.' + d, {
86337                 'default': d
86338               });
86339             }).attr('checked', false);
86340             enter.append('span').html(function (d) {
86341               return field.t.html('options.' + d, {
86342                 'default': d
86343               });
86344             });
86345             labels = labels.merge(enter);
86346             radios = labels.selectAll('input').on('change', changeRadio);
86347           }
86348
86349           function structureExtras(selection, tags) {
86350             var selected = selectedKey() || tags.layer !== undefined;
86351             var type = _mainPresetIndex.field(selected);
86352             var layer = _mainPresetIndex.field('layer');
86353             var showLayer = selected === 'bridge' || selected === 'tunnel' || tags.layer !== undefined;
86354             var extrasWrap = selection.selectAll('.structure-extras-wrap').data(selected ? [0] : []);
86355             extrasWrap.exit().remove();
86356             extrasWrap = extrasWrap.enter().append('div').attr('class', 'structure-extras-wrap').merge(extrasWrap);
86357             var list = extrasWrap.selectAll('ul').data([0]);
86358             list = list.enter().append('ul').attr('class', 'rows').merge(list); // Type
86359
86360             if (type) {
86361               if (!typeField || typeField.id !== selected) {
86362                 typeField = uiField(context, type, _entityIDs, {
86363                   wrap: false
86364                 }).on('change', changeType);
86365               }
86366
86367               typeField.tags(tags);
86368             } else {
86369               typeField = null;
86370             }
86371
86372             var typeItem = list.selectAll('.structure-type-item').data(typeField ? [typeField] : [], function (d) {
86373               return d.id;
86374             }); // Exit
86375
86376             typeItem.exit().remove(); // Enter
86377
86378             var typeEnter = typeItem.enter().insert('li', ':first-child').attr('class', 'labeled-input structure-type-item');
86379             typeEnter.append('span').attr('class', 'label structure-label-type').attr('for', 'preset-input-' + selected).html(_t.html('inspector.radio.structure.type'));
86380             typeEnter.append('div').attr('class', 'structure-input-type-wrap'); // Update
86381
86382             typeItem = typeItem.merge(typeEnter);
86383
86384             if (typeField) {
86385               typeItem.selectAll('.structure-input-type-wrap').call(typeField.render);
86386             } // Layer
86387
86388
86389             if (layer && showLayer) {
86390               if (!layerField) {
86391                 layerField = uiField(context, layer, _entityIDs, {
86392                   wrap: false
86393                 }).on('change', changeLayer);
86394               }
86395
86396               layerField.tags(tags);
86397               field.keys = utilArrayUnion(field.keys, ['layer']);
86398             } else {
86399               layerField = null;
86400               field.keys = field.keys.filter(function (k) {
86401                 return k !== 'layer';
86402               });
86403             }
86404
86405             var layerItem = list.selectAll('.structure-layer-item').data(layerField ? [layerField] : []); // Exit
86406
86407             layerItem.exit().remove(); // Enter
86408
86409             var layerEnter = layerItem.enter().append('li').attr('class', 'labeled-input structure-layer-item');
86410             layerEnter.append('span').attr('class', 'label structure-label-layer').attr('for', 'preset-input-layer').html(_t.html('inspector.radio.structure.layer'));
86411             layerEnter.append('div').attr('class', 'structure-input-layer-wrap'); // Update
86412
86413             layerItem = layerItem.merge(layerEnter);
86414
86415             if (layerField) {
86416               layerItem.selectAll('.structure-input-layer-wrap').call(layerField.render);
86417             }
86418           }
86419
86420           function changeType(t, onInput) {
86421             var key = selectedKey();
86422             if (!key) return;
86423             var val = t[key];
86424
86425             if (val !== 'no') {
86426               _oldType[key] = val;
86427             }
86428
86429             if (field.type === 'structureRadio') {
86430               // remove layer if it should not be set
86431               if (val === 'no' || key !== 'bridge' && key !== 'tunnel' || key === 'tunnel' && val === 'building_passage') {
86432                 t.layer = undefined;
86433               } // add layer if it should be set
86434
86435
86436               if (t.layer === undefined) {
86437                 if (key === 'bridge' && val !== 'no') {
86438                   t.layer = '1';
86439                 }
86440
86441                 if (key === 'tunnel' && val !== 'no' && val !== 'building_passage') {
86442                   t.layer = '-1';
86443                 }
86444               }
86445             }
86446
86447             dispatch$1.call('change', this, t, onInput);
86448           }
86449
86450           function changeLayer(t, onInput) {
86451             if (t.layer === '0') {
86452               t.layer = undefined;
86453             }
86454
86455             dispatch$1.call('change', this, t, onInput);
86456           }
86457
86458           function changeRadio() {
86459             var t = {};
86460             var activeKey;
86461
86462             if (field.key) {
86463               t[field.key] = undefined;
86464             }
86465
86466             radios.each(function (d) {
86467               var active = select(this).property('checked');
86468               if (active) activeKey = d;
86469
86470               if (field.key) {
86471                 if (active) t[field.key] = d;
86472               } else {
86473                 var val = _oldType[activeKey] || 'yes';
86474                 t[d] = active ? val : undefined;
86475               }
86476             });
86477
86478             if (field.type === 'structureRadio') {
86479               if (activeKey === 'bridge') {
86480                 t.layer = '1';
86481               } else if (activeKey === 'tunnel' && t.tunnel !== 'building_passage') {
86482                 t.layer = '-1';
86483               } else {
86484                 t.layer = undefined;
86485               }
86486             }
86487
86488             dispatch$1.call('change', this, t);
86489           }
86490
86491           radio.tags = function (tags) {
86492             radios.property('checked', function (d) {
86493               if (field.key) {
86494                 return tags[field.key] === d;
86495               }
86496
86497               return !!(typeof tags[d] === 'string' && tags[d].toLowerCase() !== 'no');
86498             });
86499
86500             function isMixed(d) {
86501               if (field.key) {
86502                 return Array.isArray(tags[field.key]) && tags[field.key].includes(d);
86503               }
86504
86505               return Array.isArray(tags[d]);
86506             }
86507
86508             labels.classed('active', function (d) {
86509               if (field.key) {
86510                 return Array.isArray(tags[field.key]) && tags[field.key].includes(d) || tags[field.key] === d;
86511               }
86512
86513               return Array.isArray(tags[d]) || !!(tags[d] && tags[d].toLowerCase() !== 'no');
86514             }).classed('mixed', isMixed).attr('title', function (d) {
86515               return isMixed(d) ? _t('inspector.unshared_value_tooltip') : null;
86516             });
86517             var selection = radios.filter(function () {
86518               return this.checked;
86519             });
86520
86521             if (selection.empty()) {
86522               placeholder.html(_t.html('inspector.none'));
86523             } else {
86524               placeholder.html(selection.attr('value'));
86525               _oldType[selection.datum()] = tags[selection.datum()];
86526             }
86527
86528             if (field.type === 'structureRadio') {
86529               // For waterways without a tunnel tag, set 'culvert' as
86530               // the _oldType to default to if the user picks 'tunnel'
86531               if (!!tags.waterway && !_oldType.tunnel) {
86532                 _oldType.tunnel = 'culvert';
86533               }
86534
86535               wrap.call(structureExtras, tags);
86536             }
86537           };
86538
86539           radio.focus = function () {
86540             radios.node().focus();
86541           };
86542
86543           radio.entityIDs = function (val) {
86544             if (!arguments.length) return _entityIDs;
86545             _entityIDs = val;
86546             _oldType = {};
86547             return radio;
86548           };
86549
86550           radio.isAllowed = function () {
86551             return _entityIDs.length === 1;
86552           };
86553
86554           return utilRebind(radio, dispatch$1, 'on');
86555         }
86556
86557         function uiFieldRestrictions(field, context) {
86558           var dispatch$1 = dispatch('change');
86559           var breathe = behaviorBreathe();
86560           corePreferences('turn-restriction-via-way', null); // remove old key
86561
86562           var storedViaWay = corePreferences('turn-restriction-via-way0'); // use new key #6922
86563
86564           var storedDistance = corePreferences('turn-restriction-distance');
86565
86566           var _maxViaWay = storedViaWay !== null ? +storedViaWay : 0;
86567
86568           var _maxDistance = storedDistance ? +storedDistance : 30;
86569
86570           var _initialized = false;
86571
86572           var _parent = select(null); // the entire field
86573
86574
86575           var _container = select(null); // just the map
86576
86577
86578           var _oldTurns;
86579
86580           var _graph;
86581
86582           var _vertexID;
86583
86584           var _intersection;
86585
86586           var _fromWayID;
86587
86588           var _lastXPos;
86589
86590           function restrictions(selection) {
86591             _parent = selection; // try to reuse the intersection, but always rebuild it if the graph has changed
86592
86593             if (_vertexID && (context.graph() !== _graph || !_intersection)) {
86594               _graph = context.graph();
86595               _intersection = osmIntersection(_graph, _vertexID, _maxDistance);
86596             } // It's possible for there to be no actual intersection here.
86597             // for example, a vertex of two `highway=path`
86598             // In this case, hide the field.
86599
86600
86601             var isOK = _intersection && _intersection.vertices.length && // has vertices
86602             _intersection.vertices // has the vertex that the user selected
86603             .filter(function (vertex) {
86604               return vertex.id === _vertexID;
86605             }).length && _intersection.ways.length > 2 && // has more than 2 ways
86606             _intersection.ways // has more than 1 TO way
86607             .filter(function (way) {
86608               return way.__to;
86609             }).length > 1; // Also hide in the case where
86610
86611             select(selection.node().parentNode).classed('hide', !isOK); // if form field is hidden or has detached from dom, clean up.
86612
86613             if (!isOK || !context.container().select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode || !selection.node().parentNode.parentNode) {
86614               selection.call(restrictions.off);
86615               return;
86616             }
86617
86618             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
86619             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
86620             var container = wrap.selectAll('.restriction-container').data([0]); // enter
86621
86622             var containerEnter = container.enter().append('div').attr('class', 'restriction-container');
86623             containerEnter.append('div').attr('class', 'restriction-help'); // update
86624
86625             _container = containerEnter.merge(container).call(renderViewer);
86626             var controls = wrap.selectAll('.restriction-controls').data([0]); // enter/update
86627
86628             controls.enter().append('div').attr('class', 'restriction-controls-container').append('div').attr('class', 'restriction-controls').merge(controls).call(renderControls);
86629           }
86630
86631           function renderControls(selection) {
86632             var distControl = selection.selectAll('.restriction-distance').data([0]);
86633             distControl.exit().remove();
86634             var distControlEnter = distControl.enter().append('div').attr('class', 'restriction-control restriction-distance');
86635             distControlEnter.append('span').attr('class', 'restriction-control-label restriction-distance-label').html(_t.html('restriction.controls.distance') + ':');
86636             distControlEnter.append('input').attr('class', 'restriction-distance-input').attr('type', 'range').attr('min', '20').attr('max', '50').attr('step', '5');
86637             distControlEnter.append('span').attr('class', 'restriction-distance-text'); // update
86638
86639             selection.selectAll('.restriction-distance-input').property('value', _maxDistance).on('input', function () {
86640               var val = select(this).property('value');
86641               _maxDistance = +val;
86642               _intersection = null;
86643
86644               _container.selectAll('.layer-osm .layer-turns *').remove();
86645
86646               corePreferences('turn-restriction-distance', _maxDistance);
86647
86648               _parent.call(restrictions);
86649             });
86650             selection.selectAll('.restriction-distance-text').html(displayMaxDistance(_maxDistance));
86651             var viaControl = selection.selectAll('.restriction-via-way').data([0]);
86652             viaControl.exit().remove();
86653             var viaControlEnter = viaControl.enter().append('div').attr('class', 'restriction-control restriction-via-way');
86654             viaControlEnter.append('span').attr('class', 'restriction-control-label restriction-via-way-label').html(_t.html('restriction.controls.via') + ':');
86655             viaControlEnter.append('input').attr('class', 'restriction-via-way-input').attr('type', 'range').attr('min', '0').attr('max', '2').attr('step', '1');
86656             viaControlEnter.append('span').attr('class', 'restriction-via-way-text'); // update
86657
86658             selection.selectAll('.restriction-via-way-input').property('value', _maxViaWay).on('input', function () {
86659               var val = select(this).property('value');
86660               _maxViaWay = +val;
86661
86662               _container.selectAll('.layer-osm .layer-turns *').remove();
86663
86664               corePreferences('turn-restriction-via-way0', _maxViaWay);
86665
86666               _parent.call(restrictions);
86667             });
86668             selection.selectAll('.restriction-via-way-text').html(displayMaxVia(_maxViaWay));
86669           }
86670
86671           function renderViewer(selection) {
86672             if (!_intersection) return;
86673             var vgraph = _intersection.graph;
86674             var filter = utilFunctor(true);
86675             var projection = geoRawMercator(); // Reflow warning: `utilGetDimensions` calls `getBoundingClientRect`
86676             // Instead of asking the restriction-container for its dimensions,
86677             //  we can ask the .sidebar, which can have its dimensions cached.
86678             // width: calc as sidebar - padding
86679             // height: hardcoded (from `80_app.css`)
86680             // var d = utilGetDimensions(selection);
86681
86682             var sdims = utilGetDimensions(context.container().select('.sidebar'));
86683             var d = [sdims[0] - 50, 370];
86684             var c = geoVecScale(d, 0.5);
86685             var z = 22;
86686             projection.scale(geoZoomToScale(z)); // Calculate extent of all key vertices
86687
86688             var extent = geoExtent();
86689
86690             for (var i = 0; i < _intersection.vertices.length; i++) {
86691               extent._extend(_intersection.vertices[i].extent());
86692             } // If this is a large intersection, adjust zoom to fit extent
86693
86694
86695             if (_intersection.vertices.length > 1) {
86696               var padding = 180; // in z22 pixels
86697
86698               var tl = projection([extent[0][0], extent[1][1]]);
86699               var br = projection([extent[1][0], extent[0][1]]);
86700               var hFactor = (br[0] - tl[0]) / (d[0] - padding);
86701               var vFactor = (br[1] - tl[1]) / (d[1] - padding);
86702               var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
86703               var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
86704               z = z - Math.max(hZoomDiff, vZoomDiff);
86705               projection.scale(geoZoomToScale(z));
86706             }
86707
86708             var padTop = 35; // reserve top space for hint text
86709
86710             var extentCenter = projection(extent.center());
86711             extentCenter[1] = extentCenter[1] - padTop;
86712             projection.translate(geoVecSubtract(c, extentCenter)).clipExtent([[0, 0], d]);
86713             var drawLayers = svgLayers(projection, context).only(['osm', 'touch']).dimensions(d);
86714             var drawVertices = svgVertices(projection, context);
86715             var drawLines = svgLines(projection, context);
86716             var drawTurns = svgTurns(projection, context);
86717             var firstTime = selection.selectAll('.surface').empty();
86718             selection.call(drawLayers);
86719             var surface = selection.selectAll('.surface').classed('tr', true);
86720
86721             if (firstTime) {
86722               _initialized = true;
86723               surface.call(breathe);
86724             } // This can happen if we've lowered the detail while a FROM way
86725             // is selected, and that way is no longer part of the intersection.
86726
86727
86728             if (_fromWayID && !vgraph.hasEntity(_fromWayID)) {
86729               _fromWayID = null;
86730               _oldTurns = null;
86731             }
86732
86733             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));
86734             surface.on('click.restrictions', click).on('mouseover.restrictions', mouseover);
86735             surface.selectAll('.selected').classed('selected', false);
86736             surface.selectAll('.related').classed('related', false);
86737             var way;
86738
86739             if (_fromWayID) {
86740               way = vgraph.entity(_fromWayID);
86741               surface.selectAll('.' + _fromWayID).classed('selected', true).classed('related', true);
86742             }
86743
86744             document.addEventListener('resizeWindow', function () {
86745               utilSetDimensions(_container, null);
86746               redraw(1);
86747             }, false);
86748             updateHints(null);
86749
86750             function click(d3_event) {
86751               surface.call(breathe.off).call(breathe);
86752               var datum = d3_event.target.__data__;
86753               var entity = datum && datum.properties && datum.properties.entity;
86754
86755               if (entity) {
86756                 datum = entity;
86757               }
86758
86759               if (datum instanceof osmWay && (datum.__from || datum.__via)) {
86760                 _fromWayID = datum.id;
86761                 _oldTurns = null;
86762                 redraw();
86763               } else if (datum instanceof osmTurn) {
86764                 var actions, extraActions, turns, i;
86765                 var restrictionType = osmInferRestriction(vgraph, datum, projection);
86766
86767                 if (datum.restrictionID && !datum.direct) {
86768                   return;
86769                 } else if (datum.restrictionID && !datum.only) {
86770                   // NO -> ONLY
86771                   var seen = {};
86772                   var datumOnly = JSON.parse(JSON.stringify(datum)); // deep clone the datum
86773
86774                   datumOnly.only = true; // but change this property
86775
86776                   restrictionType = restrictionType.replace(/^no/, 'only'); // Adding an ONLY restriction should destroy all other direct restrictions from the FROM towards the VIA.
86777                   // We will remember them in _oldTurns, and restore them if the user clicks again.
86778
86779                   turns = _intersection.turns(_fromWayID, 2);
86780                   extraActions = [];
86781                   _oldTurns = [];
86782
86783                   for (i = 0; i < turns.length; i++) {
86784                     var turn = turns[i];
86785                     if (seen[turn.restrictionID]) continue; // avoid deleting the turn twice (#4968, #4928)
86786
86787                     if (turn.direct && turn.path[1] === datum.path[1]) {
86788                       seen[turns[i].restrictionID] = true;
86789                       turn.restrictionType = osmInferRestriction(vgraph, turn, projection);
86790
86791                       _oldTurns.push(turn);
86792
86793                       extraActions.push(actionUnrestrictTurn(turn));
86794                     }
86795                   }
86796
86797                   actions = _intersection.actions.concat(extraActions, [actionRestrictTurn(datumOnly, restrictionType), _t('operations.restriction.annotation.create')]);
86798                 } else if (datum.restrictionID) {
86799                   // ONLY -> Allowed
86800                   // Restore whatever restrictions we might have destroyed by cycling thru the ONLY state.
86801                   // This relies on the assumption that the intersection was already split up when we
86802                   // performed the previous action (NO -> ONLY), so the IDs in _oldTurns shouldn't have changed.
86803                   turns = _oldTurns || [];
86804                   extraActions = [];
86805
86806                   for (i = 0; i < turns.length; i++) {
86807                     if (turns[i].key !== datum.key) {
86808                       extraActions.push(actionRestrictTurn(turns[i], turns[i].restrictionType));
86809                     }
86810                   }
86811
86812                   _oldTurns = null;
86813                   actions = _intersection.actions.concat(extraActions, [actionUnrestrictTurn(datum), _t('operations.restriction.annotation.delete')]);
86814                 } else {
86815                   // Allowed -> NO
86816                   actions = _intersection.actions.concat([actionRestrictTurn(datum, restrictionType), _t('operations.restriction.annotation.create')]);
86817                 }
86818
86819                 context.perform.apply(context, actions); // At this point the datum will be changed, but will have same key..
86820                 // Refresh it and update the help..
86821
86822                 var s = surface.selectAll('.' + datum.key);
86823                 datum = s.empty() ? null : s.datum();
86824                 updateHints(datum);
86825               } else {
86826                 _fromWayID = null;
86827                 _oldTurns = null;
86828                 redraw();
86829               }
86830             }
86831
86832             function mouseover(d3_event) {
86833               var datum = d3_event.target.__data__;
86834               updateHints(datum);
86835             }
86836
86837             _lastXPos = _lastXPos || sdims[0];
86838
86839             function redraw(minChange) {
86840               var xPos = -1;
86841
86842               if (minChange) {
86843                 xPos = utilGetDimensions(context.container().select('.sidebar'))[0];
86844               }
86845
86846               if (!minChange || minChange && Math.abs(xPos - _lastXPos) >= minChange) {
86847                 if (context.hasEntity(_vertexID)) {
86848                   _lastXPos = xPos;
86849
86850                   _container.call(renderViewer);
86851                 }
86852               }
86853             }
86854
86855             function highlightPathsFrom(wayID) {
86856               surface.selectAll('.related').classed('related', false).classed('allow', false).classed('restrict', false).classed('only', false);
86857               surface.selectAll('.' + wayID).classed('related', true);
86858
86859               if (wayID) {
86860                 var turns = _intersection.turns(wayID, _maxViaWay);
86861
86862                 for (var i = 0; i < turns.length; i++) {
86863                   var turn = turns[i];
86864                   var ids = [turn.to.way];
86865                   var klass = turn.no ? 'restrict' : turn.only ? 'only' : 'allow';
86866
86867                   if (turn.only || turns.length === 1) {
86868                     if (turn.via.ways) {
86869                       ids = ids.concat(turn.via.ways);
86870                     }
86871                   } else if (turn.to.way === wayID) {
86872                     continue;
86873                   }
86874
86875                   surface.selectAll(utilEntitySelector(ids)).classed('related', true).classed('allow', klass === 'allow').classed('restrict', klass === 'restrict').classed('only', klass === 'only');
86876                 }
86877               }
86878             }
86879
86880             function updateHints(datum) {
86881               var help = _container.selectAll('.restriction-help').html('');
86882
86883               var placeholders = {};
86884               ['from', 'via', 'to'].forEach(function (k) {
86885                 placeholders[k] = '<span class="qualifier">' + _t('restriction.help.' + k) + '</span>';
86886               });
86887               var entity = datum && datum.properties && datum.properties.entity;
86888
86889               if (entity) {
86890                 datum = entity;
86891               }
86892
86893               if (_fromWayID) {
86894                 way = vgraph.entity(_fromWayID);
86895                 surface.selectAll('.' + _fromWayID).classed('selected', true).classed('related', true);
86896               } // Hovering a way
86897
86898
86899               if (datum instanceof osmWay && datum.__from) {
86900                 way = datum;
86901                 highlightPathsFrom(_fromWayID ? null : way.id);
86902                 surface.selectAll('.' + way.id).classed('related', true);
86903                 var clickSelect = !_fromWayID || _fromWayID !== way.id;
86904                 help.append('div') // "Click to select FROM {fromName}." / "FROM {fromName}"
86905                 .html(_t.html('restriction.help.' + (clickSelect ? 'select_from_name' : 'from_name'), {
86906                   from: placeholders.from,
86907                   fromName: displayName(way.id, vgraph)
86908                 })); // Hovering a turn arrow
86909               } else if (datum instanceof osmTurn) {
86910                 var restrictionType = osmInferRestriction(vgraph, datum, projection);
86911                 var turnType = restrictionType.replace(/^(only|no)\_/, '');
86912                 var indirect = datum.direct === false ? _t.html('restriction.help.indirect') : '';
86913                 var klass, turnText, nextText;
86914
86915                 if (datum.no) {
86916                   klass = 'restrict';
86917                   turnText = _t.html('restriction.help.turn.no_' + turnType, {
86918                     indirect: indirect
86919                   });
86920                   nextText = _t.html('restriction.help.turn.only_' + turnType, {
86921                     indirect: ''
86922                   });
86923                 } else if (datum.only) {
86924                   klass = 'only';
86925                   turnText = _t.html('restriction.help.turn.only_' + turnType, {
86926                     indirect: indirect
86927                   });
86928                   nextText = _t.html('restriction.help.turn.allowed_' + turnType, {
86929                     indirect: ''
86930                   });
86931                 } else {
86932                   klass = 'allow';
86933                   turnText = _t.html('restriction.help.turn.allowed_' + turnType, {
86934                     indirect: indirect
86935                   });
86936                   nextText = _t.html('restriction.help.turn.no_' + turnType, {
86937                     indirect: ''
86938                   });
86939                 }
86940
86941                 help.append('div') // "NO Right Turn (indirect)"
86942                 .attr('class', 'qualifier ' + klass).html(turnText);
86943                 help.append('div') // "FROM {fromName} TO {toName}"
86944                 .html(_t.html('restriction.help.from_name_to_name', {
86945                   from: placeholders.from,
86946                   fromName: displayName(datum.from.way, vgraph),
86947                   to: placeholders.to,
86948                   toName: displayName(datum.to.way, vgraph)
86949                 }));
86950
86951                 if (datum.via.ways && datum.via.ways.length) {
86952                   var names = [];
86953
86954                   for (var i = 0; i < datum.via.ways.length; i++) {
86955                     var prev = names[names.length - 1];
86956                     var curr = displayName(datum.via.ways[i], vgraph);
86957                     if (!prev || curr !== prev) // collapse identical names
86958                       names.push(curr);
86959                   }
86960
86961                   help.append('div') // "VIA {viaNames}"
86962                   .html(_t.html('restriction.help.via_names', {
86963                     via: placeholders.via,
86964                     viaNames: names.join(', ')
86965                   }));
86966                 }
86967
86968                 if (!indirect) {
86969                   help.append('div') // Click for "No Right Turn"
86970                   .html(_t.html('restriction.help.toggle', {
86971                     turn: nextText.trim()
86972                   }));
86973                 }
86974
86975                 highlightPathsFrom(null);
86976                 var alongIDs = datum.path.slice();
86977                 surface.selectAll(utilEntitySelector(alongIDs)).classed('related', true).classed('allow', klass === 'allow').classed('restrict', klass === 'restrict').classed('only', klass === 'only'); // Hovering empty surface
86978               } else {
86979                 highlightPathsFrom(null);
86980
86981                 if (_fromWayID) {
86982                   help.append('div') // "FROM {fromName}"
86983                   .html(_t.html('restriction.help.from_name', {
86984                     from: placeholders.from,
86985                     fromName: displayName(_fromWayID, vgraph)
86986                   }));
86987                 } else {
86988                   help.append('div') // "Click to select a FROM segment."
86989                   .html(_t.html('restriction.help.select_from', {
86990                     from: placeholders.from
86991                   }));
86992                 }
86993               }
86994             }
86995           }
86996
86997           function displayMaxDistance(maxDist) {
86998             var isImperial = !_mainLocalizer.usesMetric();
86999             var opts;
87000
87001             if (isImperial) {
87002               var distToFeet = {
87003                 // imprecise conversion for prettier display
87004                 20: 70,
87005                 25: 85,
87006                 30: 100,
87007                 35: 115,
87008                 40: 130,
87009                 45: 145,
87010                 50: 160
87011               }[maxDist];
87012               opts = {
87013                 distance: _t('units.feet', {
87014                   quantity: distToFeet
87015                 })
87016               };
87017             } else {
87018               opts = {
87019                 distance: _t('units.meters', {
87020                   quantity: maxDist
87021                 })
87022               };
87023             }
87024
87025             return _t.html('restriction.controls.distance_up_to', opts);
87026           }
87027
87028           function displayMaxVia(maxVia) {
87029             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');
87030           }
87031
87032           function displayName(entityID, graph) {
87033             var entity = graph.entity(entityID);
87034             var name = utilDisplayName(entity) || '';
87035             var matched = _mainPresetIndex.match(entity, graph);
87036             var type = matched && matched.name() || utilDisplayType(entity.id);
87037             return name || type;
87038           }
87039
87040           restrictions.entityIDs = function (val) {
87041             _intersection = null;
87042             _fromWayID = null;
87043             _oldTurns = null;
87044             _vertexID = val[0];
87045           };
87046
87047           restrictions.tags = function () {};
87048
87049           restrictions.focus = function () {};
87050
87051           restrictions.off = function (selection) {
87052             if (!_initialized) return;
87053             selection.selectAll('.surface').call(breathe.off).on('click.restrictions', null).on('mouseover.restrictions', null);
87054             select(window).on('resize.restrictions', null);
87055           };
87056
87057           return utilRebind(restrictions, dispatch$1, 'on');
87058         }
87059         uiFieldRestrictions.supportsMultiselection = false;
87060
87061         function uiFieldTextarea(field, context) {
87062           var dispatch$1 = dispatch('change');
87063           var input = select(null);
87064
87065           var _tags;
87066
87067           function textarea(selection) {
87068             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
87069             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
87070             input = wrap.selectAll('textarea').data([0]);
87071             input = input.enter().append('textarea').attr('id', field.domId).call(utilNoAuto).on('input', change(true)).on('blur', change()).on('change', change()).merge(input);
87072           }
87073
87074           function change(onInput) {
87075             return function () {
87076               var val = utilGetSetValue(input);
87077               if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
87078
87079               if (!val && Array.isArray(_tags[field.key])) return;
87080               var t = {};
87081               t[field.key] = val || undefined;
87082               dispatch$1.call('change', this, t, onInput);
87083             };
87084           }
87085
87086           textarea.tags = function (tags) {
87087             _tags = tags;
87088             var isMixed = Array.isArray(tags[field.key]);
87089             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);
87090           };
87091
87092           textarea.focus = function () {
87093             input.node().focus();
87094           };
87095
87096           return utilRebind(textarea, dispatch$1, 'on');
87097         }
87098
87099         function uiFieldWikidata(field, context) {
87100           var wikidata = services.wikidata;
87101           var dispatch$1 = dispatch('change');
87102
87103           var _selection = select(null);
87104
87105           var _searchInput = select(null);
87106
87107           var _qid = null;
87108           var _wikidataEntity = null;
87109           var _wikiURL = '';
87110           var _entityIDs = [];
87111
87112           var _wikipediaKey = field.keys && field.keys.find(function (key) {
87113             return key.includes('wikipedia');
87114           }),
87115               _hintKey = field.key === 'wikidata' ? 'name' : field.key.split(':')[0];
87116
87117           var combobox = uiCombobox(context, 'combo-' + field.safeid).caseSensitive(true).minItems(1);
87118
87119           function wiki(selection) {
87120             _selection = selection;
87121             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
87122             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
87123             var list = wrap.selectAll('ul').data([0]);
87124             list = list.enter().append('ul').attr('class', 'rows').merge(list);
87125             var searchRow = list.selectAll('li.wikidata-search').data([0]);
87126             var searchRowEnter = searchRow.enter().append('li').attr('class', 'wikidata-search');
87127             searchRowEnter.append('input').attr('type', 'text').attr('id', field.domId).style('flex', '1').call(utilNoAuto).on('focus', function () {
87128               var node = select(this).node();
87129               node.setSelectionRange(0, node.value.length);
87130             }).on('blur', function () {
87131               setLabelForEntity();
87132             }).call(combobox.fetcher(fetchWikidataItems));
87133             combobox.on('accept', function (d) {
87134               if (d) {
87135                 _qid = d.id;
87136                 change();
87137               }
87138             }).on('cancel', function () {
87139               setLabelForEntity();
87140             });
87141             searchRowEnter.append('button').attr('class', 'form-field-button wiki-link').attr('title', _t('icons.view_on', {
87142               domain: 'wikidata.org'
87143             })).call(svgIcon('#iD-icon-out-link')).on('click', function (d3_event) {
87144               d3_event.preventDefault();
87145               if (_wikiURL) window.open(_wikiURL, '_blank');
87146             });
87147             searchRow = searchRow.merge(searchRowEnter);
87148             _searchInput = searchRow.select('input');
87149             var wikidataProperties = ['description', 'identifier'];
87150             var items = list.selectAll('li.labeled-input').data(wikidataProperties); // Enter
87151
87152             var enter = items.enter().append('li').attr('class', function (d) {
87153               return 'labeled-input preset-wikidata-' + d;
87154             });
87155             enter.append('span').attr('class', 'label').html(function (d) {
87156               return _t.html('wikidata.' + d);
87157             });
87158             enter.append('input').attr('type', 'text').call(utilNoAuto).classed('disabled', 'true').attr('readonly', 'true');
87159             enter.append('button').attr('class', 'form-field-button').attr('title', _t('icons.copy')).call(svgIcon('#iD-operation-copy')).on('click', function (d3_event) {
87160               d3_event.preventDefault();
87161               select(this.parentNode).select('input').node().select();
87162               document.execCommand('copy');
87163             });
87164           }
87165
87166           function fetchWikidataItems(q, callback) {
87167             if (!q && _hintKey) {
87168               // other tags may be good search terms
87169               for (var i in _entityIDs) {
87170                 var entity = context.hasEntity(_entityIDs[i]);
87171
87172                 if (entity.tags[_hintKey]) {
87173                   q = entity.tags[_hintKey];
87174                   break;
87175                 }
87176               }
87177             }
87178
87179             wikidata.itemsForSearchQuery(q, function (err, data) {
87180               if (err) return;
87181
87182               for (var i in data) {
87183                 data[i].value = data[i].label + ' (' + data[i].id + ')';
87184                 data[i].title = data[i].description;
87185               }
87186
87187               if (callback) callback(data);
87188             });
87189           }
87190
87191           function change() {
87192             var syncTags = {};
87193             syncTags[field.key] = _qid;
87194             dispatch$1.call('change', this, syncTags); // attempt asynchronous update of wikidata tag..
87195
87196             var initGraph = context.graph();
87197             var initEntityIDs = _entityIDs;
87198             wikidata.entityByQID(_qid, function (err, entity) {
87199               if (err) return; // If graph has changed, we can't apply this update.
87200
87201               if (context.graph() !== initGraph) return;
87202               if (!entity.sitelinks) return;
87203               var langs = wikidata.languagesToQuery(); // use the label and description languages as fallbacks
87204
87205               ['labels', 'descriptions'].forEach(function (key) {
87206                 if (!entity[key]) return;
87207                 var valueLangs = Object.keys(entity[key]);
87208                 if (valueLangs.length === 0) return;
87209                 var valueLang = valueLangs[0];
87210
87211                 if (langs.indexOf(valueLang) === -1) {
87212                   langs.push(valueLang);
87213                 }
87214               });
87215               var newWikipediaValue;
87216
87217               if (_wikipediaKey) {
87218                 var foundPreferred;
87219
87220                 for (var i in langs) {
87221                   var lang = langs[i];
87222                   var siteID = lang.replace('-', '_') + 'wiki';
87223
87224                   if (entity.sitelinks[siteID]) {
87225                     foundPreferred = true;
87226                     newWikipediaValue = lang + ':' + entity.sitelinks[siteID].title; // use the first match
87227
87228                     break;
87229                   }
87230                 }
87231
87232                 if (!foundPreferred) {
87233                   // No wikipedia sites available in the user's language or the fallback languages,
87234                   // default to any wikipedia sitelink
87235                   var wikiSiteKeys = Object.keys(entity.sitelinks).filter(function (site) {
87236                     return site.endsWith('wiki');
87237                   });
87238
87239                   if (wikiSiteKeys.length === 0) {
87240                     // if no wikipedia pages are linked to this wikidata entity, delete that tag
87241                     newWikipediaValue = null;
87242                   } else {
87243                     var wikiLang = wikiSiteKeys[0].slice(0, -4).replace('_', '-');
87244                     var wikiTitle = entity.sitelinks[wikiSiteKeys[0]].title;
87245                     newWikipediaValue = wikiLang + ':' + wikiTitle;
87246                   }
87247                 }
87248               }
87249
87250               if (newWikipediaValue) {
87251                 newWikipediaValue = context.cleanTagValue(newWikipediaValue);
87252               }
87253
87254               if (typeof newWikipediaValue === 'undefined') return;
87255               var actions = initEntityIDs.map(function (entityID) {
87256                 var entity = context.hasEntity(entityID);
87257                 if (!entity) return null;
87258                 var currTags = Object.assign({}, entity.tags); // shallow copy
87259
87260                 if (newWikipediaValue === null) {
87261                   if (!currTags[_wikipediaKey]) return null;
87262                   delete currTags[_wikipediaKey];
87263                 } else {
87264                   currTags[_wikipediaKey] = newWikipediaValue;
87265                 }
87266
87267                 return actionChangeTags(entityID, currTags);
87268               }).filter(Boolean);
87269               if (!actions.length) return; // Coalesce the update of wikidata tag into the previous tag change
87270
87271               context.overwrite(function actionUpdateWikipediaTags(graph) {
87272                 actions.forEach(function (action) {
87273                   graph = action(graph);
87274                 });
87275                 return graph;
87276               }, context.history().undoAnnotation()); // do not dispatch.call('change') here, because entity_editor
87277               // changeTags() is not intended to be called asynchronously
87278             });
87279           }
87280
87281           function setLabelForEntity() {
87282             var label = '';
87283
87284             if (_wikidataEntity) {
87285               label = entityPropertyForDisplay(_wikidataEntity, 'labels');
87286
87287               if (label.length === 0) {
87288                 label = _wikidataEntity.id.toString();
87289               }
87290             }
87291
87292             utilGetSetValue(_searchInput, label);
87293           }
87294
87295           wiki.tags = function (tags) {
87296             var isMixed = Array.isArray(tags[field.key]);
87297
87298             _searchInput.attr('title', isMixed ? tags[field.key].filter(Boolean).join('\n') : null).attr('placeholder', isMixed ? _t('inspector.multiple_values') : '').classed('mixed', isMixed);
87299
87300             _qid = typeof tags[field.key] === 'string' && tags[field.key] || '';
87301
87302             if (!/^Q[0-9]*$/.test(_qid)) {
87303               // not a proper QID
87304               unrecognized();
87305               return;
87306             } // QID value in correct format
87307
87308
87309             _wikiURL = 'https://wikidata.org/wiki/' + _qid;
87310             wikidata.entityByQID(_qid, function (err, entity) {
87311               if (err) {
87312                 unrecognized();
87313                 return;
87314               }
87315
87316               _wikidataEntity = entity;
87317               setLabelForEntity();
87318               var description = entityPropertyForDisplay(entity, 'descriptions');
87319
87320               _selection.select('button.wiki-link').classed('disabled', false);
87321
87322               _selection.select('.preset-wikidata-description').style('display', function () {
87323                 return description.length > 0 ? 'flex' : 'none';
87324               }).select('input').attr('value', description);
87325
87326               _selection.select('.preset-wikidata-identifier').style('display', function () {
87327                 return entity.id ? 'flex' : 'none';
87328               }).select('input').attr('value', entity.id);
87329             }); // not a proper QID
87330
87331             function unrecognized() {
87332               _wikidataEntity = null;
87333               setLabelForEntity();
87334
87335               _selection.select('.preset-wikidata-description').style('display', 'none');
87336
87337               _selection.select('.preset-wikidata-identifier').style('display', 'none');
87338
87339               _selection.select('button.wiki-link').classed('disabled', true);
87340
87341               if (_qid && _qid !== '') {
87342                 _wikiURL = 'https://wikidata.org/wiki/Special:Search?search=' + _qid;
87343               } else {
87344                 _wikiURL = '';
87345               }
87346             }
87347           };
87348
87349           function entityPropertyForDisplay(wikidataEntity, propKey) {
87350             if (!wikidataEntity[propKey]) return '';
87351             var propObj = wikidataEntity[propKey];
87352             var langKeys = Object.keys(propObj);
87353             if (langKeys.length === 0) return ''; // sorted by priority, since we want to show the user's language first if possible
87354
87355             var langs = wikidata.languagesToQuery();
87356
87357             for (var i in langs) {
87358               var lang = langs[i];
87359               var valueObj = propObj[lang];
87360               if (valueObj && valueObj.value && valueObj.value.length > 0) return valueObj.value;
87361             } // default to any available value
87362
87363
87364             return propObj[langKeys[0]].value;
87365           }
87366
87367           wiki.entityIDs = function (val) {
87368             if (!arguments.length) return _entityIDs;
87369             _entityIDs = val;
87370             return wiki;
87371           };
87372
87373           wiki.focus = function () {
87374             _searchInput.node().focus();
87375           };
87376
87377           return utilRebind(wiki, dispatch$1, 'on');
87378         }
87379
87380         function uiFieldWikipedia(field, context) {
87381           var _arguments = arguments;
87382           var dispatch$1 = dispatch('change');
87383           var wikipedia = services.wikipedia;
87384           var wikidata = services.wikidata;
87385
87386           var _langInput = select(null);
87387
87388           var _titleInput = select(null);
87389
87390           var _wikiURL = '';
87391
87392           var _entityIDs;
87393
87394           var _tags;
87395
87396           var _dataWikipedia = [];
87397           _mainFileFetcher.get('wmf_sitematrix').then(function (d) {
87398             _dataWikipedia = d;
87399             if (_tags) updateForTags(_tags);
87400           })["catch"](function () {
87401             /* ignore */
87402           });
87403           var langCombo = uiCombobox(context, 'wikipedia-lang').fetcher(function (value, callback) {
87404             var v = value.toLowerCase();
87405             callback(_dataWikipedia.filter(function (d) {
87406               return d[0].toLowerCase().indexOf(v) >= 0 || d[1].toLowerCase().indexOf(v) >= 0 || d[2].toLowerCase().indexOf(v) >= 0;
87407             }).map(function (d) {
87408               return {
87409                 value: d[1]
87410               };
87411             }));
87412           });
87413           var titleCombo = uiCombobox(context, 'wikipedia-title').fetcher(function (value, callback) {
87414             if (!value) {
87415               value = '';
87416
87417               for (var i in _entityIDs) {
87418                 var entity = context.hasEntity(_entityIDs[i]);
87419
87420                 if (entity.tags.name) {
87421                   value = entity.tags.name;
87422                   break;
87423                 }
87424               }
87425             }
87426
87427             var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
87428             searchfn(language()[2], value, function (query, data) {
87429               callback(data.map(function (d) {
87430                 return {
87431                   value: d
87432                 };
87433               }));
87434             });
87435           });
87436
87437           function wiki(selection) {
87438             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
87439             wrap = wrap.enter().append('div').attr('class', "form-field-input-wrap form-field-input-".concat(field.type)).merge(wrap);
87440             var langContainer = wrap.selectAll('.wiki-lang-container').data([0]);
87441             langContainer = langContainer.enter().append('div').attr('class', 'wiki-lang-container').merge(langContainer);
87442             _langInput = langContainer.selectAll('input.wiki-lang').data([0]);
87443             _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);
87444
87445             _langInput.on('blur', changeLang).on('change', changeLang);
87446
87447             var titleContainer = wrap.selectAll('.wiki-title-container').data([0]);
87448             titleContainer = titleContainer.enter().append('div').attr('class', 'wiki-title-container').merge(titleContainer);
87449             _titleInput = titleContainer.selectAll('input.wiki-title').data([0]);
87450             _titleInput = _titleInput.enter().append('input').attr('type', 'text').attr('class', 'wiki-title').attr('id', field.domId).call(utilNoAuto).call(titleCombo).merge(_titleInput);
87451
87452             _titleInput.on('blur', function () {
87453               change(true);
87454             }).on('change', function () {
87455               change(false);
87456             });
87457
87458             var link = titleContainer.selectAll('.wiki-link').data([0]);
87459             link = link.enter().append('button').attr('class', 'form-field-button wiki-link').attr('title', _t('icons.view_on', {
87460               domain: 'wikipedia.org'
87461             })).call(svgIcon('#iD-icon-out-link')).merge(link);
87462             link.on('click', function (d3_event) {
87463               d3_event.preventDefault();
87464               if (_wikiURL) window.open(_wikiURL, '_blank');
87465             });
87466           }
87467
87468           function defaultLanguageInfo(skipEnglishFallback) {
87469             var langCode = _mainLocalizer.languageCode().toLowerCase();
87470
87471             for (var i in _dataWikipedia) {
87472               var d = _dataWikipedia[i]; // default to the language of iD's current locale
87473
87474               if (d[2] === langCode) return d;
87475             } // fallback to English
87476
87477
87478             return skipEnglishFallback ? ['', '', ''] : ['English', 'English', 'en'];
87479           }
87480
87481           function language(skipEnglishFallback) {
87482             var value = utilGetSetValue(_langInput).toLowerCase();
87483
87484             for (var i in _dataWikipedia) {
87485               var d = _dataWikipedia[i]; // return the language already set in the UI, if supported
87486
87487               if (d[0].toLowerCase() === value || d[1].toLowerCase() === value || d[2] === value) return d;
87488             } // fallback to English
87489
87490
87491             return defaultLanguageInfo(skipEnglishFallback);
87492           }
87493
87494           function changeLang() {
87495             utilGetSetValue(_langInput, language()[1]);
87496             change(true);
87497           }
87498
87499           function change(skipWikidata) {
87500             var value = utilGetSetValue(_titleInput);
87501             var m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/);
87502
87503             var langInfo = m && _dataWikipedia.find(function (d) {
87504               return m[1] === d[2];
87505             });
87506
87507             var syncTags = {};
87508
87509             if (langInfo) {
87510               var nativeLangName = langInfo[1]; // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
87511
87512               value = decodeURIComponent(m[2]).replace(/_/g, ' ');
87513
87514               if (m[3]) {
87515                 var anchor; // try {
87516                 // leave this out for now - #6232
87517                 // Best-effort `anchordecode:` implementation
87518                 // anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
87519                 // } catch (e) {
87520
87521                 anchor = decodeURIComponent(m[3]); // }
87522
87523                 value += '#' + anchor.replace(/_/g, ' ');
87524               }
87525
87526               value = value.slice(0, 1).toUpperCase() + value.slice(1);
87527               utilGetSetValue(_langInput, nativeLangName);
87528               utilGetSetValue(_titleInput, value);
87529             }
87530
87531             if (value) {
87532               syncTags.wikipedia = context.cleanTagValue(language()[2] + ':' + value);
87533             } else {
87534               syncTags.wikipedia = undefined;
87535             }
87536
87537             dispatch$1.call('change', this, syncTags);
87538             if (skipWikidata || !value || !language()[2]) return; // attempt asynchronous update of wikidata tag..
87539
87540             var initGraph = context.graph();
87541             var initEntityIDs = _entityIDs;
87542             wikidata.itemsByTitle(language()[2], value, function (err, data) {
87543               if (err || !data || !Object.keys(data).length) return; // If graph has changed, we can't apply this update.
87544
87545               if (context.graph() !== initGraph) return;
87546               var qids = Object.keys(data);
87547               var value = qids && qids.find(function (id) {
87548                 return id.match(/^Q\d+$/);
87549               });
87550               var actions = initEntityIDs.map(function (entityID) {
87551                 var entity = context.entity(entityID).tags;
87552                 var currTags = Object.assign({}, entity); // shallow copy
87553
87554                 if (currTags.wikidata !== value) {
87555                   currTags.wikidata = value;
87556                   return actionChangeTags(entityID, currTags);
87557                 }
87558
87559                 return null;
87560               }).filter(Boolean);
87561               if (!actions.length) return; // Coalesce the update of wikidata tag into the previous tag change
87562
87563               context.overwrite(function actionUpdateWikidataTags(graph) {
87564                 actions.forEach(function (action) {
87565                   graph = action(graph);
87566                 });
87567                 return graph;
87568               }, context.history().undoAnnotation()); // do not dispatch.call('change') here, because entity_editor
87569               // changeTags() is not intended to be called asynchronously
87570             });
87571           }
87572
87573           wiki.tags = function (tags) {
87574             _tags = tags;
87575             updateForTags(tags);
87576           };
87577
87578           function updateForTags(tags) {
87579             var value = typeof tags[field.key] === 'string' ? tags[field.key] : ''; // Expect tag format of `tagLang:tagArticleTitle`, e.g. `fr:Paris`, with
87580             // optional suffix of `#anchor`
87581
87582             var m = value.match(/([^:]+):([^#]+)(?:#(.+))?/);
87583             var tagLang = m && m[1];
87584             var tagArticleTitle = m && m[2];
87585             var anchor = m && m[3];
87586
87587             var tagLangInfo = tagLang && _dataWikipedia.find(function (d) {
87588               return tagLang === d[2];
87589             }); // value in correct format
87590
87591
87592             if (tagLangInfo) {
87593               var nativeLangName = tagLangInfo[1];
87594               utilGetSetValue(_langInput, nativeLangName);
87595               utilGetSetValue(_titleInput, tagArticleTitle + (anchor ? '#' + anchor : ''));
87596
87597               if (anchor) {
87598                 try {
87599                   // Best-effort `anchorencode:` implementation
87600                   anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
87601                 } catch (e) {
87602                   anchor = anchor.replace(/ /g, '_');
87603                 }
87604               }
87605
87606               _wikiURL = 'https://' + tagLang + '.wikipedia.org/wiki/' + tagArticleTitle.replace(/ /g, '_') + (anchor ? '#' + anchor : ''); // unrecognized value format
87607             } else {
87608               utilGetSetValue(_titleInput, value);
87609
87610               if (value && value !== '') {
87611                 utilGetSetValue(_langInput, '');
87612                 var defaultLangInfo = defaultLanguageInfo();
87613                 _wikiURL = "https://".concat(defaultLangInfo[2], ".wikipedia.org/w/index.php?fulltext=1&search=").concat(value);
87614               } else {
87615                 var shownOrDefaultLangInfo = language(true
87616                 /* skipEnglishFallback */
87617                 );
87618                 utilGetSetValue(_langInput, shownOrDefaultLangInfo[1]);
87619                 _wikiURL = '';
87620               }
87621             }
87622           }
87623
87624           wiki.entityIDs = function (val) {
87625             if (!_arguments.length) return _entityIDs;
87626             _entityIDs = val;
87627             return wiki;
87628           };
87629
87630           wiki.focus = function () {
87631             _titleInput.node().focus();
87632           };
87633
87634           return utilRebind(wiki, dispatch$1, 'on');
87635         }
87636         uiFieldWikipedia.supportsMultiselection = false;
87637
87638         var uiFields = {
87639           access: uiFieldAccess,
87640           address: uiFieldAddress,
87641           check: uiFieldCheck,
87642           combo: uiFieldCombo,
87643           cycleway: uiFieldCycleway,
87644           defaultCheck: uiFieldCheck,
87645           email: uiFieldText,
87646           identifier: uiFieldText,
87647           lanes: uiFieldLanes,
87648           localized: uiFieldLocalized,
87649           maxspeed: uiFieldMaxspeed,
87650           manyCombo: uiFieldCombo,
87651           multiCombo: uiFieldCombo,
87652           networkCombo: uiFieldCombo,
87653           number: uiFieldText,
87654           onewayCheck: uiFieldCheck,
87655           radio: uiFieldRadio,
87656           restrictions: uiFieldRestrictions,
87657           semiCombo: uiFieldCombo,
87658           structureRadio: uiFieldRadio,
87659           tel: uiFieldText,
87660           text: uiFieldText,
87661           textarea: uiFieldTextarea,
87662           typeCombo: uiFieldCombo,
87663           url: uiFieldText,
87664           wikidata: uiFieldWikidata,
87665           wikipedia: uiFieldWikipedia
87666         };
87667
87668         function uiField(context, presetField, entityIDs, options) {
87669           options = Object.assign({
87670             show: true,
87671             wrap: true,
87672             remove: true,
87673             revert: true,
87674             info: true
87675           }, options);
87676           var dispatch$1 = dispatch('change', 'revert');
87677           var field = Object.assign({}, presetField); // shallow copy
87678
87679           field.domId = utilUniqueDomId('form-field-' + field.safeid);
87680           var _show = options.show;
87681           var _state = '';
87682           var _tags = {};
87683           var _locked = false;
87684
87685           var _lockedTip = uiTooltip().title(_t.html('inspector.lock.suggestion', {
87686             label: field.label
87687           })).placement('bottom');
87688
87689           field.keys = field.keys || [field.key]; // only create the fields that are actually being shown
87690
87691           if (_show && !field.impl) {
87692             createField();
87693           } // Creates the field.. This is done lazily,
87694           // once we know that the field will be shown.
87695
87696
87697           function createField() {
87698             field.impl = uiFields[field.type](field, context).on('change', function (t, onInput) {
87699               dispatch$1.call('change', field, t, onInput);
87700             });
87701
87702             if (entityIDs) {
87703               field.entityIDs = entityIDs; // if this field cares about the entities, pass them along
87704
87705               if (field.impl.entityIDs) {
87706                 field.impl.entityIDs(entityIDs);
87707               }
87708             }
87709           }
87710
87711           function isModified() {
87712             if (!entityIDs || !entityIDs.length) return false;
87713             return entityIDs.some(function (entityID) {
87714               var original = context.graph().base().entities[entityID];
87715               var latest = context.graph().entity(entityID);
87716               return field.keys.some(function (key) {
87717                 return original ? latest.tags[key] !== original.tags[key] : latest.tags[key];
87718               });
87719             });
87720           }
87721
87722           function tagsContainFieldKey() {
87723             return field.keys.some(function (key) {
87724               if (field.type === 'multiCombo') {
87725                 for (var tagKey in _tags) {
87726                   if (tagKey.indexOf(key) === 0) {
87727                     return true;
87728                   }
87729                 }
87730
87731                 return false;
87732               }
87733
87734               return _tags[key] !== undefined;
87735             });
87736           }
87737
87738           function revert(d3_event, d) {
87739             d3_event.stopPropagation();
87740             d3_event.preventDefault();
87741             if (!entityIDs || _locked) return;
87742             dispatch$1.call('revert', d, d.keys);
87743           }
87744
87745           function remove(d3_event, d) {
87746             d3_event.stopPropagation();
87747             d3_event.preventDefault();
87748             if (_locked) return;
87749             var t = {};
87750             d.keys.forEach(function (key) {
87751               t[key] = undefined;
87752             });
87753             dispatch$1.call('change', d, t);
87754           }
87755
87756           field.render = function (selection) {
87757             var container = selection.selectAll('.form-field').data([field]); // Enter
87758
87759             var enter = container.enter().append('div').attr('class', function (d) {
87760               return 'form-field form-field-' + d.safeid;
87761             }).classed('nowrap', !options.wrap);
87762
87763             if (options.wrap) {
87764               var labelEnter = enter.append('label').attr('class', 'field-label').attr('for', function (d) {
87765                 return d.domId;
87766               });
87767               var textEnter = labelEnter.append('span').attr('class', 'label-text');
87768               textEnter.append('span').attr('class', 'label-textvalue').html(function (d) {
87769                 return d.label();
87770               });
87771               textEnter.append('span').attr('class', 'label-textannotation');
87772
87773               if (options.remove) {
87774                 labelEnter.append('button').attr('class', 'remove-icon').attr('title', _t('icons.remove')).call(svgIcon('#iD-operation-delete'));
87775               }
87776
87777               if (options.revert) {
87778                 labelEnter.append('button').attr('class', 'modified-icon').attr('title', _t('icons.undo')).call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-redo' : '#iD-icon-undo'));
87779               }
87780             } // Update
87781
87782
87783             container = container.merge(enter);
87784             container.select('.field-label > .remove-icon') // propagate bound data
87785             .on('click', remove);
87786             container.select('.field-label > .modified-icon') // propagate bound data
87787             .on('click', revert);
87788             container.each(function (d) {
87789               var selection = select(this);
87790
87791               if (!d.impl) {
87792                 createField();
87793               }
87794
87795               var reference, help; // instantiate field help
87796
87797               if (options.wrap && field.type === 'restrictions') {
87798                 help = uiFieldHelp(context, 'restrictions');
87799               } // instantiate tag reference
87800
87801
87802               if (options.wrap && options.info) {
87803                 var referenceKey = d.key || '';
87804
87805                 if (d.type === 'multiCombo') {
87806                   // lookup key without the trailing ':'
87807                   referenceKey = referenceKey.replace(/:$/, '');
87808                 }
87809
87810                 reference = uiTagReference(d.reference || {
87811                   key: referenceKey
87812                 });
87813
87814                 if (_state === 'hover') {
87815                   reference.showing(false);
87816                 }
87817               }
87818
87819               selection.call(d.impl); // add field help components
87820
87821               if (help) {
87822                 selection.call(help.body).select('.field-label').call(help.button);
87823               } // add tag reference components
87824
87825
87826               if (reference) {
87827                 selection.call(reference.body).select('.field-label').call(reference.button);
87828               }
87829
87830               d.impl.tags(_tags);
87831             });
87832             container.classed('locked', _locked).classed('modified', isModified()).classed('present', tagsContainFieldKey()); // show a tip and lock icon if the field is locked
87833
87834             var annotation = container.selectAll('.field-label .label-textannotation');
87835             var icon = annotation.selectAll('.icon').data(_locked ? [0] : []);
87836             icon.exit().remove();
87837             icon.enter().append('svg').attr('class', 'icon').append('use').attr('xlink:href', '#fas-lock');
87838             container.call(_locked ? _lockedTip : _lockedTip.destroy);
87839           };
87840
87841           field.state = function (val) {
87842             if (!arguments.length) return _state;
87843             _state = val;
87844             return field;
87845           };
87846
87847           field.tags = function (val) {
87848             if (!arguments.length) return _tags;
87849             _tags = val;
87850
87851             if (tagsContainFieldKey() && !_show) {
87852               // always show a field if it has a value to display
87853               _show = true;
87854
87855               if (!field.impl) {
87856                 createField();
87857               }
87858             }
87859
87860             return field;
87861           };
87862
87863           field.locked = function (val) {
87864             if (!arguments.length) return _locked;
87865             _locked = val;
87866             return field;
87867           };
87868
87869           field.show = function () {
87870             _show = true;
87871
87872             if (!field.impl) {
87873               createField();
87874             }
87875
87876             if (field["default"] && field.key && _tags[field.key] !== field["default"]) {
87877               var t = {};
87878               t[field.key] = field["default"];
87879               dispatch$1.call('change', this, t);
87880             }
87881           }; // A shown field has a visible UI, a non-shown field is in the 'Add field' dropdown
87882
87883
87884           field.isShown = function () {
87885             return _show;
87886           }; // An allowed field can appear in the UI or in the 'Add field' dropdown.
87887           // A non-allowed field is hidden from the user altogether
87888
87889
87890           field.isAllowed = function () {
87891             if (entityIDs && entityIDs.length > 1 && uiFields[field.type].supportsMultiselection === false) return false;
87892             if (field.geometry && !entityIDs.every(function (entityID) {
87893               return field.matchGeometry(context.graph().geometry(entityID));
87894             })) return false;
87895
87896             if (field.countryCodes || field.notCountryCodes) {
87897               var extent = combinedEntityExtent();
87898               if (!extent) return true;
87899               var center = extent.center();
87900               var countryCode = iso1A2Code(center);
87901               if (!countryCode) return false;
87902               countryCode = countryCode.toLowerCase();
87903
87904               if (field.countryCodes && field.countryCodes.indexOf(countryCode) === -1) {
87905                 return false;
87906               }
87907
87908               if (field.notCountryCodes && field.notCountryCodes.indexOf(countryCode) !== -1) {
87909                 return false;
87910               }
87911             }
87912
87913             var prerequisiteTag = field.prerequisiteTag;
87914
87915             if (entityIDs && !tagsContainFieldKey() && // ignore tagging prerequisites if a value is already present
87916             prerequisiteTag) {
87917               if (!entityIDs.every(function (entityID) {
87918                 var entity = context.graph().entity(entityID);
87919
87920                 if (prerequisiteTag.key) {
87921                   var value = entity.tags[prerequisiteTag.key];
87922                   if (!value) return false;
87923
87924                   if (prerequisiteTag.valueNot) {
87925                     return prerequisiteTag.valueNot !== value;
87926                   }
87927
87928                   if (prerequisiteTag.value) {
87929                     return prerequisiteTag.value === value;
87930                   }
87931                 } else if (prerequisiteTag.keyNot) {
87932                   if (entity.tags[prerequisiteTag.keyNot]) return false;
87933                 }
87934
87935                 return true;
87936               })) return false;
87937             }
87938
87939             return true;
87940           };
87941
87942           field.focus = function () {
87943             if (field.impl) {
87944               field.impl.focus();
87945             }
87946           };
87947
87948           function combinedEntityExtent() {
87949             return entityIDs && entityIDs.length && entityIDs.reduce(function (extent, entityID) {
87950               var entity = context.graph().entity(entityID);
87951               return extent.extend(entity.extent(context.graph()));
87952             }, geoExtent());
87953           }
87954
87955           return utilRebind(field, dispatch$1, 'on');
87956         }
87957
87958         function uiFormFields(context) {
87959           var moreCombo = uiCombobox(context, 'more-fields').minItems(1);
87960           var _fieldsArr = [];
87961           var _lastPlaceholder = '';
87962           var _state = '';
87963           var _klass = '';
87964
87965           function formFields(selection) {
87966             var allowedFields = _fieldsArr.filter(function (field) {
87967               return field.isAllowed();
87968             });
87969
87970             var shown = allowedFields.filter(function (field) {
87971               return field.isShown();
87972             });
87973             var notShown = allowedFields.filter(function (field) {
87974               return !field.isShown();
87975             });
87976             var container = selection.selectAll('.form-fields-container').data([0]);
87977             container = container.enter().append('div').attr('class', 'form-fields-container ' + (_klass || '')).merge(container);
87978             var fields = container.selectAll('.wrap-form-field').data(shown, function (d) {
87979               return d.id + (d.entityIDs ? d.entityIDs.join() : '');
87980             });
87981             fields.exit().remove(); // Enter
87982
87983             var enter = fields.enter().append('div').attr('class', function (d) {
87984               return 'wrap-form-field wrap-form-field-' + d.safeid;
87985             }); // Update
87986
87987             fields = fields.merge(enter);
87988             fields.order().each(function (d) {
87989               select(this).call(d.render);
87990             });
87991             var titles = [];
87992             var moreFields = notShown.map(function (field) {
87993               var title = field.title();
87994               titles.push(title);
87995               var terms = field.terms();
87996               if (field.key) terms.push(field.key);
87997               if (field.keys) terms = terms.concat(field.keys);
87998               return {
87999                 display: field.label(),
88000                 value: title,
88001                 title: title,
88002                 field: field,
88003                 terms: terms
88004               };
88005             });
88006             var placeholder = titles.slice(0, 3).join(', ') + (titles.length > 3 ? '…' : '');
88007             var more = selection.selectAll('.more-fields').data(_state === 'hover' || moreFields.length === 0 ? [] : [0]);
88008             more.exit().remove();
88009             var moreEnter = more.enter().append('div').attr('class', 'more-fields').append('label');
88010             moreEnter.append('span').html(_t.html('inspector.add_fields'));
88011             more = moreEnter.merge(more);
88012             var input = more.selectAll('.value').data([0]);
88013             input.exit().remove();
88014             input = input.enter().append('input').attr('class', 'value').attr('type', 'text').attr('placeholder', placeholder).call(utilNoAuto).merge(input);
88015             input.call(utilGetSetValue, '').call(moreCombo.data(moreFields).on('accept', function (d) {
88016               if (!d) return; // user entered something that was not matched
88017
88018               var field = d.field;
88019               field.show();
88020               selection.call(formFields); // rerender
88021
88022               field.focus();
88023             })); // avoid updating placeholder excessively (triggers style recalc)
88024
88025             if (_lastPlaceholder !== placeholder) {
88026               input.attr('placeholder', placeholder);
88027               _lastPlaceholder = placeholder;
88028             }
88029           }
88030
88031           formFields.fieldsArr = function (val) {
88032             if (!arguments.length) return _fieldsArr;
88033             _fieldsArr = val || [];
88034             return formFields;
88035           };
88036
88037           formFields.state = function (val) {
88038             if (!arguments.length) return _state;
88039             _state = val;
88040             return formFields;
88041           };
88042
88043           formFields.klass = function (val) {
88044             if (!arguments.length) return _klass;
88045             _klass = val;
88046             return formFields;
88047           };
88048
88049           return formFields;
88050         }
88051
88052         function uiSectionPresetFields(context) {
88053           var section = uiSection('preset-fields', context).label(_t.html('inspector.fields')).disclosureContent(renderDisclosureContent);
88054           var dispatch$1 = dispatch('change', 'revert');
88055           var formFields = uiFormFields(context);
88056
88057           var _state;
88058
88059           var _fieldsArr;
88060
88061           var _presets = [];
88062
88063           var _tags;
88064
88065           var _entityIDs;
88066
88067           function renderDisclosureContent(selection) {
88068             if (!_fieldsArr) {
88069               var graph = context.graph();
88070               var geometries = Object.keys(_entityIDs.reduce(function (geoms, entityID) {
88071                 geoms[graph.entity(entityID).geometry(graph)] = true;
88072                 return geoms;
88073               }, {}));
88074               var presetsManager = _mainPresetIndex;
88075               var allFields = [];
88076               var allMoreFields = [];
88077               var sharedTotalFields;
88078
88079               _presets.forEach(function (preset) {
88080                 var fields = preset.fields();
88081                 var moreFields = preset.moreFields();
88082                 allFields = utilArrayUnion(allFields, fields);
88083                 allMoreFields = utilArrayUnion(allMoreFields, moreFields);
88084
88085                 if (!sharedTotalFields) {
88086                   sharedTotalFields = utilArrayUnion(fields, moreFields);
88087                 } else {
88088                   sharedTotalFields = sharedTotalFields.filter(function (field) {
88089                     return fields.indexOf(field) !== -1 || moreFields.indexOf(field) !== -1;
88090                   });
88091                 }
88092               });
88093
88094               var sharedFields = allFields.filter(function (field) {
88095                 return sharedTotalFields.indexOf(field) !== -1;
88096               });
88097               var sharedMoreFields = allMoreFields.filter(function (field) {
88098                 return sharedTotalFields.indexOf(field) !== -1;
88099               });
88100               _fieldsArr = [];
88101               sharedFields.forEach(function (field) {
88102                 if (field.matchAllGeometry(geometries)) {
88103                   _fieldsArr.push(uiField(context, field, _entityIDs));
88104                 }
88105               });
88106               var singularEntity = _entityIDs.length === 1 && graph.hasEntity(_entityIDs[0]);
88107
88108               if (singularEntity && singularEntity.isHighwayIntersection(graph) && presetsManager.field('restrictions')) {
88109                 _fieldsArr.push(uiField(context, presetsManager.field('restrictions'), _entityIDs));
88110               }
88111
88112               var additionalFields = utilArrayUnion(sharedMoreFields, presetsManager.universal());
88113               additionalFields.sort(function (field1, field2) {
88114                 return field1.label().localeCompare(field2.label(), _mainLocalizer.localeCode());
88115               });
88116               additionalFields.forEach(function (field) {
88117                 if (sharedFields.indexOf(field) === -1 && field.matchAllGeometry(geometries)) {
88118                   _fieldsArr.push(uiField(context, field, _entityIDs, {
88119                     show: false
88120                   }));
88121                 }
88122               });
88123
88124               _fieldsArr.forEach(function (field) {
88125                 field.on('change', function (t, onInput) {
88126                   dispatch$1.call('change', field, _entityIDs, t, onInput);
88127                 }).on('revert', function (keys) {
88128                   dispatch$1.call('revert', field, keys);
88129                 });
88130               });
88131             }
88132
88133             _fieldsArr.forEach(function (field) {
88134               field.state(_state).tags(_tags);
88135             });
88136
88137             selection.call(formFields.fieldsArr(_fieldsArr).state(_state).klass('grouped-items-area'));
88138             selection.selectAll('.wrap-form-field input').on('keydown', function (d3_event) {
88139               // if user presses enter, and combobox is not active, accept edits..
88140               if (d3_event.keyCode === 13 && // ↩ Return
88141               context.container().select('.combobox').empty()) {
88142                 context.enter(modeBrowse(context));
88143               }
88144             });
88145           }
88146
88147           section.presets = function (val) {
88148             if (!arguments.length) return _presets;
88149
88150             if (!_presets || !val || !utilArrayIdentical(_presets, val)) {
88151               _presets = val;
88152               _fieldsArr = null;
88153             }
88154
88155             return section;
88156           };
88157
88158           section.state = function (val) {
88159             if (!arguments.length) return _state;
88160             _state = val;
88161             return section;
88162           };
88163
88164           section.tags = function (val) {
88165             if (!arguments.length) return _tags;
88166             _tags = val; // Don't reset _fieldsArr here.
88167
88168             return section;
88169           };
88170
88171           section.entityIDs = function (val) {
88172             if (!arguments.length) return _entityIDs;
88173
88174             if (!val || !_entityIDs || !utilArrayIdentical(_entityIDs, val)) {
88175               _entityIDs = val;
88176               _fieldsArr = null;
88177             }
88178
88179             return section;
88180           };
88181
88182           return utilRebind(section, dispatch$1, 'on');
88183         }
88184
88185         function uiSectionRawMemberEditor(context) {
88186           var section = uiSection('raw-member-editor', context).shouldDisplay(function () {
88187             if (!_entityIDs || _entityIDs.length !== 1) return false;
88188             var entity = context.hasEntity(_entityIDs[0]);
88189             return entity && entity.type === 'relation';
88190           }).label(function () {
88191             var entity = context.hasEntity(_entityIDs[0]);
88192             if (!entity) return '';
88193             var gt = entity.members.length > _maxMembers ? '>' : '';
88194             var count = gt + entity.members.slice(0, _maxMembers).length;
88195             return _t('inspector.title_count', {
88196               title: _t.html('inspector.members'),
88197               count: count
88198             });
88199           }).disclosureContent(renderDisclosureContent);
88200           var taginfo = services.taginfo;
88201
88202           var _entityIDs;
88203
88204           var _maxMembers = 1000;
88205
88206           function downloadMember(d3_event, d) {
88207             d3_event.preventDefault(); // display the loading indicator
88208
88209             select(this.parentNode).classed('tag-reference-loading', true);
88210             context.loadEntity(d.id, function () {
88211               section.reRender();
88212             });
88213           }
88214
88215           function zoomToMember(d3_event, d) {
88216             d3_event.preventDefault();
88217             var entity = context.entity(d.id);
88218             context.map().zoomToEase(entity); // highlight the feature in case it wasn't previously on-screen
88219
88220             utilHighlightEntities([d.id], true, context);
88221           }
88222
88223           function selectMember(d3_event, d) {
88224             d3_event.preventDefault(); // remove the hover-highlight styling
88225
88226             utilHighlightEntities([d.id], false, context);
88227             var entity = context.entity(d.id);
88228             var mapExtent = context.map().extent();
88229
88230             if (!entity.intersects(mapExtent, context.graph())) {
88231               // zoom to the entity if its extent is not visible now
88232               context.map().zoomToEase(entity);
88233             }
88234
88235             context.enter(modeSelect(context, [d.id]));
88236           }
88237
88238           function changeRole(d3_event, d) {
88239             var oldRole = d.role;
88240             var newRole = context.cleanRelationRole(select(this).property('value'));
88241
88242             if (oldRole !== newRole) {
88243               var member = {
88244                 id: d.id,
88245                 type: d.type,
88246                 role: newRole
88247               };
88248               context.perform(actionChangeMember(d.relation.id, member, d.index), _t('operations.change_role.annotation', {
88249                 n: 1
88250               }));
88251               context.validator().validate();
88252             }
88253           }
88254
88255           function deleteMember(d3_event, d) {
88256             // remove the hover-highlight styling
88257             utilHighlightEntities([d.id], false, context);
88258             context.perform(actionDeleteMember(d.relation.id, d.index), _t('operations.delete_member.annotation', {
88259               n: 1
88260             }));
88261
88262             if (!context.hasEntity(d.relation.id)) {
88263               // Removing the last member will also delete the relation.
88264               // If this happens we need to exit the selection mode
88265               context.enter(modeBrowse(context));
88266             } else {
88267               // Changing the mode also runs `validate`, but otherwise we need to
88268               // rerun it manually
88269               context.validator().validate();
88270             }
88271           }
88272
88273           function renderDisclosureContent(selection) {
88274             var entityID = _entityIDs[0];
88275             var memberships = [];
88276             var entity = context.entity(entityID);
88277             entity.members.slice(0, _maxMembers).forEach(function (member, index) {
88278               memberships.push({
88279                 index: index,
88280                 id: member.id,
88281                 type: member.type,
88282                 role: member.role,
88283                 relation: entity,
88284                 member: context.hasEntity(member.id),
88285                 domId: utilUniqueDomId(entityID + '-member-' + index)
88286               });
88287             });
88288             var list = selection.selectAll('.member-list').data([0]);
88289             list = list.enter().append('ul').attr('class', 'member-list').merge(list);
88290             var items = list.selectAll('li').data(memberships, function (d) {
88291               return osmEntity.key(d.relation) + ',' + d.index + ',' + (d.member ? osmEntity.key(d.member) : 'incomplete');
88292             });
88293             items.exit().each(unbind).remove();
88294             var itemsEnter = items.enter().append('li').attr('class', 'member-row form-field').classed('member-incomplete', function (d) {
88295               return !d.member;
88296             });
88297             itemsEnter.each(function (d) {
88298               var item = select(this);
88299               var label = item.append('label').attr('class', 'field-label').attr('for', d.domId);
88300
88301               if (d.member) {
88302                 // highlight the member feature in the map while hovering on the list item
88303                 item.on('mouseover', function () {
88304                   utilHighlightEntities([d.id], true, context);
88305                 }).on('mouseout', function () {
88306                   utilHighlightEntities([d.id], false, context);
88307                 });
88308                 var labelLink = label.append('span').attr('class', 'label-text').append('a').attr('href', '#').on('click', selectMember);
88309                 labelLink.append('span').attr('class', 'member-entity-type').html(function (d) {
88310                   var matched = _mainPresetIndex.match(d.member, context.graph());
88311                   return matched && matched.name() || utilDisplayType(d.member.id);
88312                 });
88313                 labelLink.append('span').attr('class', 'member-entity-name').html(function (d) {
88314                   return utilDisplayName(d.member);
88315                 });
88316                 label.append('button').attr('title', _t('icons.remove')).attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete'));
88317                 label.append('button').attr('class', 'member-zoom').attr('title', _t('icons.zoom_to')).call(svgIcon('#iD-icon-framed-dot', 'monochrome')).on('click', zoomToMember);
88318               } else {
88319                 var labelText = label.append('span').attr('class', 'label-text');
88320                 labelText.append('span').attr('class', 'member-entity-type').html(_t.html('inspector.' + d.type, {
88321                   id: d.id
88322                 }));
88323                 labelText.append('span').attr('class', 'member-entity-name').html(_t.html('inspector.incomplete', {
88324                   id: d.id
88325                 }));
88326                 label.append('button').attr('class', 'member-download').attr('title', _t('icons.download')).call(svgIcon('#iD-icon-load')).on('click', downloadMember);
88327               }
88328             });
88329             var wrapEnter = itemsEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
88330             wrapEnter.append('input').attr('class', 'member-role').attr('id', function (d) {
88331               return d.domId;
88332             }).property('type', 'text').attr('placeholder', _t('inspector.role')).call(utilNoAuto);
88333
88334             if (taginfo) {
88335               wrapEnter.each(bindTypeahead);
88336             } // update
88337
88338
88339             items = items.merge(itemsEnter).order();
88340             items.select('input.member-role').property('value', function (d) {
88341               return d.role;
88342             }).on('blur', changeRole).on('change', changeRole);
88343             items.select('button.member-delete').on('click', deleteMember);
88344             var dragOrigin, targetIndex;
88345             items.call(d3_drag().on('start', function (d3_event) {
88346               dragOrigin = {
88347                 x: d3_event.x,
88348                 y: d3_event.y
88349               };
88350               targetIndex = null;
88351             }).on('drag', function (d3_event) {
88352               var x = d3_event.x - dragOrigin.x,
88353                   y = d3_event.y - dragOrigin.y;
88354               if (!select(this).classed('dragging') && // don't display drag until dragging beyond a distance threshold
88355               Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return;
88356               var index = items.nodes().indexOf(this);
88357               select(this).classed('dragging', true);
88358               targetIndex = null;
88359               selection.selectAll('li.member-row').style('transform', function (d2, index2) {
88360                 var node = select(this).node();
88361
88362                 if (index === index2) {
88363                   return 'translate(' + x + 'px, ' + y + 'px)';
88364                 } else if (index2 > index && d3_event.y > node.offsetTop) {
88365                   if (targetIndex === null || index2 > targetIndex) {
88366                     targetIndex = index2;
88367                   }
88368
88369                   return 'translateY(-100%)';
88370                 } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
88371                   if (targetIndex === null || index2 < targetIndex) {
88372                     targetIndex = index2;
88373                   }
88374
88375                   return 'translateY(100%)';
88376                 }
88377
88378                 return null;
88379               });
88380             }).on('end', function (d3_event, d) {
88381               if (!select(this).classed('dragging')) return;
88382               var index = items.nodes().indexOf(this);
88383               select(this).classed('dragging', false);
88384               selection.selectAll('li.member-row').style('transform', null);
88385
88386               if (targetIndex !== null) {
88387                 // dragged to a new position, reorder
88388                 context.perform(actionMoveMember(d.relation.id, index, targetIndex), _t('operations.reorder_members.annotation'));
88389                 context.validator().validate();
88390               }
88391             }));
88392
88393             function bindTypeahead(d) {
88394               var row = select(this);
88395               var role = row.selectAll('input.member-role');
88396               var origValue = role.property('value');
88397
88398               function sort(value, data) {
88399                 var sameletter = [];
88400                 var other = [];
88401
88402                 for (var i = 0; i < data.length; i++) {
88403                   if (data[i].value.substring(0, value.length) === value) {
88404                     sameletter.push(data[i]);
88405                   } else {
88406                     other.push(data[i]);
88407                   }
88408                 }
88409
88410                 return sameletter.concat(other);
88411               }
88412
88413               role.call(uiCombobox(context, 'member-role').fetcher(function (role, callback) {
88414                 // The `geometry` param is used in the `taginfo.js` interface for
88415                 // filtering results, as a key into the `tag_members_fractions`
88416                 // object.  If we don't know the geometry because the member is
88417                 // not yet downloaded, it's ok to guess based on type.
88418                 var geometry;
88419
88420                 if (d.member) {
88421                   geometry = context.graph().geometry(d.member.id);
88422                 } else if (d.type === 'relation') {
88423                   geometry = 'relation';
88424                 } else if (d.type === 'way') {
88425                   geometry = 'line';
88426                 } else {
88427                   geometry = 'point';
88428                 }
88429
88430                 var rtype = entity.tags.type;
88431                 taginfo.roles({
88432                   debounce: true,
88433                   rtype: rtype || '',
88434                   geometry: geometry,
88435                   query: role
88436                 }, function (err, data) {
88437                   if (!err) callback(sort(role, data));
88438                 });
88439               }).on('cancel', function () {
88440                 role.property('value', origValue);
88441               }));
88442             }
88443
88444             function unbind() {
88445               var row = select(this);
88446               row.selectAll('input.member-role').call(uiCombobox.off, context);
88447             }
88448           }
88449
88450           section.entityIDs = function (val) {
88451             if (!arguments.length) return _entityIDs;
88452             _entityIDs = val;
88453             return section;
88454           };
88455
88456           return section;
88457         }
88458
88459         function actionDeleteMembers(relationId, memberIndexes) {
88460           return function (graph) {
88461             // Remove the members in descending order so removals won't shift what members
88462             // are at the remaining indexes
88463             memberIndexes.sort(function (a, b) {
88464               return b - a;
88465             });
88466
88467             for (var i in memberIndexes) {
88468               graph = actionDeleteMember(relationId, memberIndexes[i])(graph);
88469             }
88470
88471             return graph;
88472           };
88473         }
88474
88475         function uiSectionRawMembershipEditor(context) {
88476           var section = uiSection('raw-membership-editor', context).shouldDisplay(function () {
88477             return _entityIDs && _entityIDs.length;
88478           }).label(function () {
88479             var parents = getSharedParentRelations();
88480             var gt = parents.length > _maxMemberships ? '>' : '';
88481             var count = gt + parents.slice(0, _maxMemberships).length;
88482             return _t('inspector.title_count', {
88483               title: _t.html('inspector.relations'),
88484               count: count
88485             });
88486           }).disclosureContent(renderDisclosureContent);
88487           var taginfo = services.taginfo;
88488           var nearbyCombo = uiCombobox(context, 'parent-relation').minItems(1).fetcher(fetchNearbyRelations).itemsMouseEnter(function (d3_event, d) {
88489             if (d.relation) utilHighlightEntities([d.relation.id], true, context);
88490           }).itemsMouseLeave(function (d3_event, d) {
88491             if (d.relation) utilHighlightEntities([d.relation.id], false, context);
88492           });
88493           var _inChange = false;
88494           var _entityIDs = [];
88495
88496           var _showBlank;
88497
88498           var _maxMemberships = 1000;
88499
88500           function getSharedParentRelations() {
88501             var parents = [];
88502
88503             for (var i = 0; i < _entityIDs.length; i++) {
88504               var entity = context.graph().hasEntity(_entityIDs[i]);
88505               if (!entity) continue;
88506
88507               if (i === 0) {
88508                 parents = context.graph().parentRelations(entity);
88509               } else {
88510                 parents = utilArrayIntersection(parents, context.graph().parentRelations(entity));
88511               }
88512
88513               if (!parents.length) break;
88514             }
88515
88516             return parents;
88517           }
88518
88519           function getMemberships() {
88520             var memberships = [];
88521             var relations = getSharedParentRelations().slice(0, _maxMemberships);
88522             var isMultiselect = _entityIDs.length > 1;
88523             var i, relation, membership, index, member, indexedMember;
88524
88525             for (i = 0; i < relations.length; i++) {
88526               relation = relations[i];
88527               membership = {
88528                 relation: relation,
88529                 members: [],
88530                 hash: osmEntity.key(relation)
88531               };
88532
88533               for (index = 0; index < relation.members.length; index++) {
88534                 member = relation.members[index];
88535
88536                 if (_entityIDs.indexOf(member.id) !== -1) {
88537                   indexedMember = Object.assign({}, member, {
88538                     index: index
88539                   });
88540                   membership.members.push(indexedMember);
88541                   membership.hash += ',' + index.toString();
88542
88543                   if (!isMultiselect) {
88544                     // For single selections, list one entry per membership per relation.
88545                     // For multiselections, list one entry per relation.
88546                     memberships.push(membership);
88547                     membership = {
88548                       relation: relation,
88549                       members: [],
88550                       hash: osmEntity.key(relation)
88551                     };
88552                   }
88553                 }
88554               }
88555
88556               if (membership.members.length) memberships.push(membership);
88557             }
88558
88559             memberships.forEach(function (membership) {
88560               membership.domId = utilUniqueDomId('membership-' + membership.relation.id);
88561               var roles = [];
88562               membership.members.forEach(function (member) {
88563                 if (roles.indexOf(member.role) === -1) roles.push(member.role);
88564               });
88565               membership.role = roles.length === 1 ? roles[0] : roles;
88566             });
88567             return memberships;
88568           }
88569
88570           function selectRelation(d3_event, d) {
88571             d3_event.preventDefault(); // remove the hover-highlight styling
88572
88573             utilHighlightEntities([d.relation.id], false, context);
88574             context.enter(modeSelect(context, [d.relation.id]));
88575           }
88576
88577           function zoomToRelation(d3_event, d) {
88578             d3_event.preventDefault();
88579             var entity = context.entity(d.relation.id);
88580             context.map().zoomToEase(entity); // highlight the relation in case it wasn't previously on-screen
88581
88582             utilHighlightEntities([d.relation.id], true, context);
88583           }
88584
88585           function changeRole(d3_event, d) {
88586             if (d === 0) return; // called on newrow (shouldn't happen)
88587
88588             if (_inChange) return; // avoid accidental recursive call #5731
88589
88590             var newRole = context.cleanRelationRole(select(this).property('value'));
88591             if (!newRole.trim() && typeof d.role !== 'string') return;
88592             var membersToUpdate = d.members.filter(function (member) {
88593               return member.role !== newRole;
88594             });
88595
88596             if (membersToUpdate.length) {
88597               _inChange = true;
88598               context.perform(function actionChangeMemberRoles(graph) {
88599                 membersToUpdate.forEach(function (member) {
88600                   var newMember = Object.assign({}, member, {
88601                     role: newRole
88602                   });
88603                   delete newMember.index;
88604                   graph = actionChangeMember(d.relation.id, newMember, member.index)(graph);
88605                 });
88606                 return graph;
88607               }, _t('operations.change_role.annotation', {
88608                 n: membersToUpdate.length
88609               }));
88610               context.validator().validate();
88611             }
88612
88613             _inChange = false;
88614           }
88615
88616           function addMembership(d, role) {
88617             this.blur(); // avoid keeping focus on the button
88618
88619             _showBlank = false;
88620
88621             function actionAddMembers(relationId, ids, role) {
88622               return function (graph) {
88623                 for (var i in ids) {
88624                   var member = {
88625                     id: ids[i],
88626                     type: graph.entity(ids[i]).type,
88627                     role: role
88628                   };
88629                   graph = actionAddMember(relationId, member)(graph);
88630                 }
88631
88632                 return graph;
88633               };
88634             }
88635
88636             if (d.relation) {
88637               context.perform(actionAddMembers(d.relation.id, _entityIDs, role), _t('operations.add_member.annotation', {
88638                 n: _entityIDs.length
88639               }));
88640               context.validator().validate();
88641             } else {
88642               var relation = osmRelation();
88643               context.perform(actionAddEntity(relation), actionAddMembers(relation.id, _entityIDs, role), _t('operations.add.annotation.relation')); // changing the mode also runs `validate`
88644
88645               context.enter(modeSelect(context, [relation.id]).newFeature(true));
88646             }
88647           }
88648
88649           function deleteMembership(d3_event, d) {
88650             this.blur(); // avoid keeping focus on the button
88651
88652             if (d === 0) return; // called on newrow (shouldn't happen)
88653             // remove the hover-highlight styling
88654
88655             utilHighlightEntities([d.relation.id], false, context);
88656             var indexes = d.members.map(function (member) {
88657               return member.index;
88658             });
88659             context.perform(actionDeleteMembers(d.relation.id, indexes), _t('operations.delete_member.annotation', {
88660               n: _entityIDs.length
88661             }));
88662             context.validator().validate();
88663           }
88664
88665           function fetchNearbyRelations(q, callback) {
88666             var newRelation = {
88667               relation: null,
88668               value: _t('inspector.new_relation'),
88669               display: _t.html('inspector.new_relation')
88670             };
88671             var entityID = _entityIDs[0];
88672             var result = [];
88673             var graph = context.graph();
88674
88675             function baseDisplayLabel(entity) {
88676               var matched = _mainPresetIndex.match(entity, graph);
88677               var presetName = matched && matched.name() || _t('inspector.relation');
88678               var entityName = utilDisplayName(entity) || '';
88679               return presetName + ' ' + entityName;
88680             }
88681
88682             var explicitRelation = q && context.hasEntity(q.toLowerCase());
88683
88684             if (explicitRelation && explicitRelation.type === 'relation' && explicitRelation.id !== entityID) {
88685               // loaded relation is specified explicitly, only show that
88686               result.push({
88687                 relation: explicitRelation,
88688                 value: baseDisplayLabel(explicitRelation) + ' ' + explicitRelation.id
88689               });
88690             } else {
88691               context.history().intersects(context.map().extent()).forEach(function (entity) {
88692                 if (entity.type !== 'relation' || entity.id === entityID) return;
88693                 var value = baseDisplayLabel(entity);
88694                 if (q && (value + ' ' + entity.id).toLowerCase().indexOf(q.toLowerCase()) === -1) return;
88695                 result.push({
88696                   relation: entity,
88697                   value: value
88698                 });
88699               });
88700               result.sort(function (a, b) {
88701                 return osmRelation.creationOrder(a.relation, b.relation);
88702               }); // Dedupe identical names by appending relation id - see #2891
88703
88704               var dupeGroups = Object.values(utilArrayGroupBy(result, 'value')).filter(function (v) {
88705                 return v.length > 1;
88706               });
88707               dupeGroups.forEach(function (group) {
88708                 group.forEach(function (obj) {
88709                   obj.value += ' ' + obj.relation.id;
88710                 });
88711               });
88712             }
88713
88714             result.forEach(function (obj) {
88715               obj.title = obj.value;
88716             });
88717             result.unshift(newRelation);
88718             callback(result);
88719           }
88720
88721           function renderDisclosureContent(selection) {
88722             var memberships = getMemberships();
88723             var list = selection.selectAll('.member-list').data([0]);
88724             list = list.enter().append('ul').attr('class', 'member-list').merge(list);
88725             var items = list.selectAll('li.member-row-normal').data(memberships, function (d) {
88726               return d.hash;
88727             });
88728             items.exit().each(unbind).remove(); // Enter
88729
88730             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
88731
88732             itemsEnter.on('mouseover', function (d3_event, d) {
88733               utilHighlightEntities([d.relation.id], true, context);
88734             }).on('mouseout', function (d3_event, d) {
88735               utilHighlightEntities([d.relation.id], false, context);
88736             });
88737             var labelEnter = itemsEnter.append('label').attr('class', 'field-label').attr('for', function (d) {
88738               return d.domId;
88739             });
88740             var labelLink = labelEnter.append('span').attr('class', 'label-text').append('a').attr('href', '#').on('click', selectRelation);
88741             labelLink.append('span').attr('class', 'member-entity-type').html(function (d) {
88742               var matched = _mainPresetIndex.match(d.relation, context.graph());
88743               return matched && matched.name() || _t('inspector.relation');
88744             });
88745             labelLink.append('span').attr('class', 'member-entity-name').html(function (d) {
88746               return utilDisplayName(d.relation);
88747             });
88748             labelEnter.append('button').attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete')).on('click', deleteMembership);
88749             labelEnter.append('button').attr('class', 'member-zoom').attr('title', _t('icons.zoom_to')).call(svgIcon('#iD-icon-framed-dot', 'monochrome')).on('click', zoomToRelation);
88750             var wrapEnter = itemsEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
88751             wrapEnter.append('input').attr('class', 'member-role').attr('id', function (d) {
88752               return d.domId;
88753             }).property('type', 'text').property('value', function (d) {
88754               return typeof d.role === 'string' ? d.role : '';
88755             }).attr('title', function (d) {
88756               return Array.isArray(d.role) ? d.role.filter(Boolean).join('\n') : d.role;
88757             }).attr('placeholder', function (d) {
88758               return Array.isArray(d.role) ? _t('inspector.multiple_roles') : _t('inspector.role');
88759             }).classed('mixed', function (d) {
88760               return Array.isArray(d.role);
88761             }).call(utilNoAuto).on('blur', changeRole).on('change', changeRole);
88762
88763             if (taginfo) {
88764               wrapEnter.each(bindTypeahead);
88765             }
88766
88767             var newMembership = list.selectAll('.member-row-new').data(_showBlank ? [0] : []); // Exit
88768
88769             newMembership.exit().remove(); // Enter
88770
88771             var newMembershipEnter = newMembership.enter().append('li').attr('class', 'member-row member-row-new form-field');
88772             var newLabelEnter = newMembershipEnter.append('label').attr('class', 'field-label');
88773             newLabelEnter.append('input').attr('placeholder', _t('inspector.choose_relation')).attr('type', 'text').attr('class', 'member-entity-input').call(utilNoAuto);
88774             newLabelEnter.append('button').attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete')).on('click', function () {
88775               list.selectAll('.member-row-new').remove();
88776             });
88777             var newWrapEnter = newMembershipEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
88778             newWrapEnter.append('input').attr('class', 'member-role').property('type', 'text').attr('placeholder', _t('inspector.role')).call(utilNoAuto); // Update
88779
88780             newMembership = newMembership.merge(newMembershipEnter);
88781             newMembership.selectAll('.member-entity-input').on('blur', cancelEntity) // if it wasn't accepted normally, cancel it
88782             .call(nearbyCombo.on('accept', acceptEntity).on('cancel', cancelEntity)); // Container for the Add button
88783
88784             var addRow = selection.selectAll('.add-row').data([0]); // enter
88785
88786             var addRowEnter = addRow.enter().append('div').attr('class', 'add-row');
88787             var addRelationButton = addRowEnter.append('button').attr('class', 'add-relation');
88788             addRelationButton.call(svgIcon('#iD-icon-plus', 'light'));
88789             addRelationButton.call(uiTooltip().title(_t.html('inspector.add_to_relation')).placement(_mainLocalizer.textDirection() === 'ltr' ? 'right' : 'left'));
88790             addRowEnter.append('div').attr('class', 'space-value'); // preserve space
88791
88792             addRowEnter.append('div').attr('class', 'space-buttons'); // preserve space
88793             // update
88794
88795             addRow = addRow.merge(addRowEnter);
88796             addRow.select('.add-relation').on('click', function () {
88797               _showBlank = true;
88798               section.reRender();
88799               list.selectAll('.member-entity-input').node().focus();
88800             });
88801
88802             function acceptEntity(d) {
88803               if (!d) {
88804                 cancelEntity();
88805                 return;
88806               } // remove hover-higlighting
88807
88808
88809               if (d.relation) utilHighlightEntities([d.relation.id], false, context);
88810               var role = context.cleanRelationRole(list.selectAll('.member-row-new .member-role').property('value'));
88811               addMembership(d, role);
88812             }
88813
88814             function cancelEntity() {
88815               var input = newMembership.selectAll('.member-entity-input');
88816               input.property('value', ''); // remove hover-higlighting
88817
88818               context.surface().selectAll('.highlighted').classed('highlighted', false);
88819             }
88820
88821             function bindTypeahead(d) {
88822               var row = select(this);
88823               var role = row.selectAll('input.member-role');
88824               var origValue = role.property('value');
88825
88826               function sort(value, data) {
88827                 var sameletter = [];
88828                 var other = [];
88829
88830                 for (var i = 0; i < data.length; i++) {
88831                   if (data[i].value.substring(0, value.length) === value) {
88832                     sameletter.push(data[i]);
88833                   } else {
88834                     other.push(data[i]);
88835                   }
88836                 }
88837
88838                 return sameletter.concat(other);
88839               }
88840
88841               role.call(uiCombobox(context, 'member-role').fetcher(function (role, callback) {
88842                 var rtype = d.relation.tags.type;
88843                 taginfo.roles({
88844                   debounce: true,
88845                   rtype: rtype || '',
88846                   geometry: context.graph().geometry(_entityIDs[0]),
88847                   query: role
88848                 }, function (err, data) {
88849                   if (!err) callback(sort(role, data));
88850                 });
88851               }).on('cancel', function () {
88852                 role.property('value', origValue);
88853               }));
88854             }
88855
88856             function unbind() {
88857               var row = select(this);
88858               row.selectAll('input.member-role').call(uiCombobox.off, context);
88859             }
88860           }
88861
88862           section.entityIDs = function (val) {
88863             if (!arguments.length) return _entityIDs;
88864             _entityIDs = val;
88865             _showBlank = false;
88866             return section;
88867           };
88868
88869           return section;
88870         }
88871
88872         function uiSectionSelectionList(context) {
88873           var _selectedIDs = [];
88874           var section = uiSection('selected-features', context).shouldDisplay(function () {
88875             return _selectedIDs.length > 1;
88876           }).label(function () {
88877             return _t('inspector.title_count', {
88878               title: _t.html('inspector.features'),
88879               count: _selectedIDs.length
88880             });
88881           }).disclosureContent(renderDisclosureContent);
88882           context.history().on('change.selectionList', function (difference) {
88883             if (difference) {
88884               section.reRender();
88885             }
88886           });
88887
88888           section.entityIDs = function (val) {
88889             if (!arguments.length) return _selectedIDs;
88890             _selectedIDs = val;
88891             return section;
88892           };
88893
88894           function selectEntity(d3_event, entity) {
88895             context.enter(modeSelect(context, [entity.id]));
88896           }
88897
88898           function deselectEntity(d3_event, entity) {
88899             var selectedIDs = _selectedIDs.slice();
88900
88901             var index = selectedIDs.indexOf(entity.id);
88902
88903             if (index > -1) {
88904               selectedIDs.splice(index, 1);
88905               context.enter(modeSelect(context, selectedIDs));
88906             }
88907           }
88908
88909           function renderDisclosureContent(selection) {
88910             var list = selection.selectAll('.feature-list').data([0]);
88911             list = list.enter().append('ul').attr('class', 'feature-list').merge(list);
88912
88913             var entities = _selectedIDs.map(function (id) {
88914               return context.hasEntity(id);
88915             }).filter(Boolean);
88916
88917             var items = list.selectAll('.feature-list-item').data(entities, osmEntity.key);
88918             items.exit().remove(); // Enter
88919
88920             var enter = items.enter().append('li').attr('class', 'feature-list-item').each(function (d) {
88921               select(this).on('mouseover', function () {
88922                 utilHighlightEntities([d.id], true, context);
88923               }).on('mouseout', function () {
88924                 utilHighlightEntities([d.id], false, context);
88925               });
88926             });
88927             var label = enter.append('button').attr('class', 'label').on('click', selectEntity);
88928             label.append('span').attr('class', 'entity-geom-icon').call(svgIcon('', 'pre-text'));
88929             label.append('span').attr('class', 'entity-type');
88930             label.append('span').attr('class', 'entity-name');
88931             enter.append('button').attr('class', 'close').attr('title', _t('icons.deselect')).on('click', deselectEntity).call(svgIcon('#iD-icon-close')); // Update
88932
88933             items = items.merge(enter);
88934             items.selectAll('.entity-geom-icon use').attr('href', function () {
88935               var entity = this.parentNode.parentNode.__data__;
88936               return '#iD-icon-' + entity.geometry(context.graph());
88937             });
88938             items.selectAll('.entity-type').html(function (entity) {
88939               return _mainPresetIndex.match(entity, context.graph()).name();
88940             });
88941             items.selectAll('.entity-name').html(function (d) {
88942               // fetch latest entity
88943               var entity = context.entity(d.id);
88944               return utilDisplayName(entity);
88945             });
88946           }
88947
88948           return section;
88949         }
88950
88951         function uiEntityEditor(context) {
88952           var dispatch$1 = dispatch('choose');
88953           var _state = 'select';
88954           var _coalesceChanges = false;
88955           var _modified = false;
88956
88957           var _base;
88958
88959           var _entityIDs;
88960
88961           var _activePresets = [];
88962
88963           var _newFeature;
88964
88965           var _sections;
88966
88967           function entityEditor(selection) {
88968             var combinedTags = utilCombinedTags(_entityIDs, context.graph()); // Header
88969
88970             var header = selection.selectAll('.header').data([0]); // Enter
88971
88972             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
88973             headerEnter.append('button').attr('class', 'preset-reset preset-choose').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-forward' : '#iD-icon-backward'));
88974             headerEnter.append('button').attr('class', 'close').on('click', function () {
88975               context.enter(modeBrowse(context));
88976             }).call(svgIcon(_modified ? '#iD-icon-apply' : '#iD-icon-close'));
88977             headerEnter.append('h3'); // Update
88978
88979             header = header.merge(headerEnter);
88980             header.selectAll('h3').html(_entityIDs.length === 1 ? _t.html('inspector.edit') : _t.html('inspector.edit_features'));
88981             header.selectAll('.preset-reset').on('click', function () {
88982               dispatch$1.call('choose', this, _activePresets);
88983             }); // Body
88984
88985             var body = selection.selectAll('.inspector-body').data([0]); // Enter
88986
88987             var bodyEnter = body.enter().append('div').attr('class', 'entity-editor inspector-body sep-top'); // Update
88988
88989             body = body.merge(bodyEnter);
88990
88991             if (!_sections) {
88992               _sections = [uiSectionSelectionList(context), uiSectionFeatureType(context).on('choose', function (presets) {
88993                 dispatch$1.call('choose', this, presets);
88994               }), uiSectionEntityIssues(context), uiSectionPresetFields(context).on('change', changeTags).on('revert', revertTags), uiSectionRawTagEditor('raw-tag-editor', context).on('change', changeTags), uiSectionRawMemberEditor(context), uiSectionRawMembershipEditor(context)];
88995             }
88996
88997             _sections.forEach(function (section) {
88998               if (section.entityIDs) {
88999                 section.entityIDs(_entityIDs);
89000               }
89001
89002               if (section.presets) {
89003                 section.presets(_activePresets);
89004               }
89005
89006               if (section.tags) {
89007                 section.tags(combinedTags);
89008               }
89009
89010               if (section.state) {
89011                 section.state(_state);
89012               }
89013
89014               body.call(section.render);
89015             });
89016
89017             context.history().on('change.entity-editor', historyChanged);
89018
89019             function historyChanged(difference) {
89020               if (selection.selectAll('.entity-editor').empty()) return;
89021               if (_state === 'hide') return;
89022               var significant = !difference || difference.didChange.properties || difference.didChange.addition || difference.didChange.deletion;
89023               if (!significant) return;
89024               _entityIDs = _entityIDs.filter(context.hasEntity);
89025               if (!_entityIDs.length) return;
89026               var priorActivePreset = _activePresets.length === 1 && _activePresets[0];
89027               loadActivePresets();
89028               var graph = context.graph();
89029               entityEditor.modified(_base !== graph);
89030               entityEditor(selection);
89031
89032               if (priorActivePreset && _activePresets.length === 1 && priorActivePreset !== _activePresets[0]) {
89033                 // flash the button to indicate the preset changed
89034                 context.container().selectAll('.entity-editor button.preset-reset .label').style('background-color', '#fff').transition().duration(750).style('background-color', null);
89035               }
89036             }
89037           } // Tag changes that fire on input can all get coalesced into a single
89038           // history operation when the user leaves the field.  #2342
89039           // Use explicit entityIDs in case the selection changes before the event is fired.
89040
89041
89042           function changeTags(entityIDs, changed, onInput) {
89043             var actions = [];
89044
89045             for (var i in entityIDs) {
89046               var entityID = entityIDs[i];
89047               var entity = context.entity(entityID);
89048               var tags = Object.assign({}, entity.tags); // shallow copy
89049
89050               for (var k in changed) {
89051                 if (!k) continue;
89052                 var v = changed[k];
89053
89054                 if (v !== undefined || tags.hasOwnProperty(k)) {
89055                   tags[k] = v;
89056                 }
89057               }
89058
89059               if (!onInput) {
89060                 tags = utilCleanTags(tags);
89061               }
89062
89063               if (!fastDeepEqual(entity.tags, tags)) {
89064                 actions.push(actionChangeTags(entityID, tags));
89065               }
89066             }
89067
89068             if (actions.length) {
89069               var combinedAction = function combinedAction(graph) {
89070                 actions.forEach(function (action) {
89071                   graph = action(graph);
89072                 });
89073                 return graph;
89074               };
89075
89076               var annotation = _t('operations.change_tags.annotation');
89077
89078               if (_coalesceChanges) {
89079                 context.overwrite(combinedAction, annotation);
89080               } else {
89081                 context.perform(combinedAction, annotation);
89082                 _coalesceChanges = !!onInput;
89083               }
89084             } // if leaving field (blur event), rerun validation
89085
89086
89087             if (!onInput) {
89088               context.validator().validate();
89089             }
89090           }
89091
89092           function revertTags(keys) {
89093             var actions = [];
89094
89095             for (var i in _entityIDs) {
89096               var entityID = _entityIDs[i];
89097               var original = context.graph().base().entities[entityID];
89098               var changed = {};
89099
89100               for (var j in keys) {
89101                 var key = keys[j];
89102                 changed[key] = original ? original.tags[key] : undefined;
89103               }
89104
89105               var entity = context.entity(entityID);
89106               var tags = Object.assign({}, entity.tags); // shallow copy
89107
89108               for (var k in changed) {
89109                 if (!k) continue;
89110                 var v = changed[k];
89111
89112                 if (v !== undefined || tags.hasOwnProperty(k)) {
89113                   tags[k] = v;
89114                 }
89115               }
89116
89117               tags = utilCleanTags(tags);
89118
89119               if (!fastDeepEqual(entity.tags, tags)) {
89120                 actions.push(actionChangeTags(entityID, tags));
89121               }
89122             }
89123
89124             if (actions.length) {
89125               var combinedAction = function combinedAction(graph) {
89126                 actions.forEach(function (action) {
89127                   graph = action(graph);
89128                 });
89129                 return graph;
89130               };
89131
89132               var annotation = _t('operations.change_tags.annotation');
89133
89134               if (_coalesceChanges) {
89135                 context.overwrite(combinedAction, annotation);
89136               } else {
89137                 context.perform(combinedAction, annotation);
89138                 _coalesceChanges = false;
89139               }
89140             }
89141
89142             context.validator().validate();
89143           }
89144
89145           entityEditor.modified = function (val) {
89146             if (!arguments.length) return _modified;
89147             _modified = val;
89148             return entityEditor;
89149           };
89150
89151           entityEditor.state = function (val) {
89152             if (!arguments.length) return _state;
89153             _state = val;
89154             return entityEditor;
89155           };
89156
89157           entityEditor.entityIDs = function (val) {
89158             if (!arguments.length) return _entityIDs;
89159             if (val && _entityIDs && utilArrayIdentical(_entityIDs, val)) return entityEditor; // exit early if no change
89160
89161             _entityIDs = val;
89162             _base = context.graph();
89163             _coalesceChanges = false;
89164             loadActivePresets(true);
89165             return entityEditor.modified(false);
89166           };
89167
89168           entityEditor.newFeature = function (val) {
89169             if (!arguments.length) return _newFeature;
89170             _newFeature = val;
89171             return entityEditor;
89172           };
89173
89174           function loadActivePresets(isForNewSelection) {
89175             var graph = context.graph();
89176             var counts = {};
89177
89178             for (var i in _entityIDs) {
89179               var entity = graph.hasEntity(_entityIDs[i]);
89180               if (!entity) return;
89181               var match = _mainPresetIndex.match(entity, graph);
89182               if (!counts[match.id]) counts[match.id] = 0;
89183               counts[match.id] += 1;
89184             }
89185
89186             var matches = Object.keys(counts).sort(function (p1, p2) {
89187               return counts[p2] - counts[p1];
89188             }).map(function (pID) {
89189               return _mainPresetIndex.item(pID);
89190             });
89191
89192             if (!isForNewSelection) {
89193               // A "weak" preset doesn't set any tags. (e.g. "Address")
89194               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")
89195
89196               if (weakPreset && matches.length === 1 && matches[0].isFallback()) return;
89197             }
89198
89199             entityEditor.presets(matches);
89200           }
89201
89202           entityEditor.presets = function (val) {
89203             if (!arguments.length) return _activePresets; // don't reload the same preset
89204
89205             if (!utilArrayIdentical(val, _activePresets)) {
89206               _activePresets = val;
89207             }
89208
89209             return entityEditor;
89210           };
89211
89212           return utilRebind(entityEditor, dispatch$1, 'on');
89213         }
89214
89215         function uiPresetList(context) {
89216           var dispatch$1 = dispatch('cancel', 'choose');
89217
89218           var _entityIDs;
89219
89220           var _currentPresets;
89221
89222           var _autofocus = false;
89223
89224           function presetList(selection) {
89225             if (!_entityIDs) return;
89226             var presets = _mainPresetIndex.matchAllGeometry(entityGeometries());
89227             selection.html('');
89228             var messagewrap = selection.append('div').attr('class', 'header fillL');
89229             var message = messagewrap.append('h3').html(_t.html('inspector.choose'));
89230             messagewrap.append('button').attr('class', 'preset-choose').on('click', function () {
89231               dispatch$1.call('cancel', this);
89232             }).call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward'));
89233
89234             function initialKeydown(d3_event) {
89235               // hack to let delete shortcut work when search is autofocused
89236               if (search.property('value').length === 0 && (d3_event.keyCode === utilKeybinding.keyCodes['⌫'] || d3_event.keyCode === utilKeybinding.keyCodes['⌦'])) {
89237                 d3_event.preventDefault();
89238                 d3_event.stopPropagation();
89239                 operationDelete(context, _entityIDs)(); // hack to let undo work when search is autofocused
89240               } else if (search.property('value').length === 0 && (d3_event.ctrlKey || d3_event.metaKey) && d3_event.keyCode === utilKeybinding.keyCodes.z) {
89241                 d3_event.preventDefault();
89242                 d3_event.stopPropagation();
89243                 context.undo();
89244               } else if (!d3_event.ctrlKey && !d3_event.metaKey) {
89245                 // don't check for delete/undo hack on future keydown events
89246                 select(this).on('keydown', keydown);
89247                 keydown.call(this, d3_event);
89248               }
89249             }
89250
89251             function keydown(d3_event) {
89252               // down arrow
89253               if (d3_event.keyCode === utilKeybinding.keyCodes['↓'] && // if insertion point is at the end of the string
89254               search.node().selectionStart === search.property('value').length) {
89255                 d3_event.preventDefault();
89256                 d3_event.stopPropagation(); // move focus to the first item in the preset list
89257
89258                 var buttons = list.selectAll('.preset-list-button');
89259                 if (!buttons.empty()) buttons.nodes()[0].focus();
89260               }
89261             }
89262
89263             function keypress(d3_event) {
89264               // enter
89265               var value = search.property('value');
89266
89267               if (d3_event.keyCode === 13 && // ↩ Return
89268               value.length) {
89269                 list.selectAll('.preset-list-item:first-child').each(function (d) {
89270                   d.choose.call(this);
89271                 });
89272               }
89273             }
89274
89275             function inputevent() {
89276               var value = search.property('value');
89277               list.classed('filtered', value.length);
89278               var extent = combinedEntityExtent();
89279               var results, messageText;
89280
89281               if (value.length && extent) {
89282                 var center = extent.center();
89283                 var countryCode = iso1A2Code(center);
89284                 results = presets.search(value, entityGeometries()[0], countryCode && countryCode.toLowerCase());
89285                 messageText = _t('inspector.results', {
89286                   n: results.collection.length,
89287                   search: value
89288                 });
89289               } else {
89290                 results = _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro());
89291                 messageText = _t('inspector.choose');
89292               }
89293
89294               list.call(drawList, results);
89295               message.html(messageText);
89296             }
89297
89298             var searchWrap = selection.append('div').attr('class', 'search-header');
89299             searchWrap.call(svgIcon('#iD-icon-search', 'pre-text'));
89300             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);
89301
89302             if (_autofocus) {
89303               search.node().focus(); // Safari 14 doesn't always like to focus immediately,
89304               // so try again on the next pass
89305
89306               setTimeout(function () {
89307                 search.node().focus();
89308               }, 0);
89309             }
89310
89311             var listWrap = selection.append('div').attr('class', 'inspector-body');
89312             var list = listWrap.append('div').attr('class', 'preset-list').call(drawList, _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro()));
89313             context.features().on('change.preset-list', updateForFeatureHiddenState);
89314           }
89315
89316           function drawList(list, presets) {
89317             presets = presets.matchAllGeometry(entityGeometries());
89318             var collection = presets.collection.reduce(function (collection, preset) {
89319               if (!preset) return collection;
89320
89321               if (preset.members) {
89322                 if (preset.members.collection.filter(function (preset) {
89323                   return preset.addable();
89324                 }).length > 1) {
89325                   collection.push(CategoryItem(preset));
89326                 }
89327               } else if (preset.addable()) {
89328                 collection.push(PresetItem(preset));
89329               }
89330
89331               return collection;
89332             }, []);
89333             var items = list.selectAll('.preset-list-item').data(collection, function (d) {
89334               return d.preset.id;
89335             });
89336             items.order();
89337             items.exit().remove();
89338             items.enter().append('div').attr('class', function (item) {
89339               return 'preset-list-item preset-' + item.preset.id.replace('/', '-');
89340             }).classed('current', function (item) {
89341               return _currentPresets.indexOf(item.preset) !== -1;
89342             }).each(function (item) {
89343               select(this).call(item);
89344             }).style('opacity', 0).transition().style('opacity', 1);
89345             updateForFeatureHiddenState();
89346           }
89347
89348           function itemKeydown(d3_event) {
89349             // the actively focused item
89350             var item = select(this.closest('.preset-list-item'));
89351             var parentItem = select(item.node().parentNode.closest('.preset-list-item')); // arrow down, move focus to the next, lower item
89352
89353             if (d3_event.keyCode === utilKeybinding.keyCodes['↓']) {
89354               d3_event.preventDefault();
89355               d3_event.stopPropagation(); // the next item in the list at the same level
89356
89357               var nextItem = select(item.node().nextElementSibling); // if there is no next item in this list
89358
89359               if (nextItem.empty()) {
89360                 // if there is a parent item
89361                 if (!parentItem.empty()) {
89362                   // the item is the last item of a sublist,
89363                   // select the next item at the parent level
89364                   nextItem = select(parentItem.node().nextElementSibling);
89365                 } // if the focused item is expanded
89366
89367               } else if (select(this).classed('expanded')) {
89368                 // select the first subitem instead
89369                 nextItem = item.select('.subgrid .preset-list-item:first-child');
89370               }
89371
89372               if (!nextItem.empty()) {
89373                 // focus on the next item
89374                 nextItem.select('.preset-list-button').node().focus();
89375               } // arrow up, move focus to the previous, higher item
89376
89377             } else if (d3_event.keyCode === utilKeybinding.keyCodes['↑']) {
89378               d3_event.preventDefault();
89379               d3_event.stopPropagation(); // the previous item in the list at the same level
89380
89381               var previousItem = select(item.node().previousElementSibling); // if there is no previous item in this list
89382
89383               if (previousItem.empty()) {
89384                 // if there is a parent item
89385                 if (!parentItem.empty()) {
89386                   // the item is the first subitem of a sublist select the parent item
89387                   previousItem = parentItem;
89388                 } // if the previous item is expanded
89389
89390               } else if (previousItem.select('.preset-list-button').classed('expanded')) {
89391                 // select the last subitem of the sublist of the previous item
89392                 previousItem = previousItem.select('.subgrid .preset-list-item:last-child');
89393               }
89394
89395               if (!previousItem.empty()) {
89396                 // focus on the previous item
89397                 previousItem.select('.preset-list-button').node().focus();
89398               } else {
89399                 // the focus is at the top of the list, move focus back to the search field
89400                 var search = select(this.closest('.preset-list-pane')).select('.preset-search-input');
89401                 search.node().focus();
89402               } // arrow left, move focus to the parent item if there is one
89403
89404             } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '→' : '←']) {
89405               d3_event.preventDefault();
89406               d3_event.stopPropagation(); // if there is a parent item, focus on the parent item
89407
89408               if (!parentItem.empty()) {
89409                 parentItem.select('.preset-list-button').node().focus();
89410               } // arrow right, choose this item
89411
89412             } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '←' : '→']) {
89413               d3_event.preventDefault();
89414               d3_event.stopPropagation();
89415               item.datum().choose.call(select(this).node());
89416             }
89417           }
89418
89419           function CategoryItem(preset) {
89420             var box,
89421                 sublist,
89422                 shown = false;
89423
89424             function item(selection) {
89425               var wrap = selection.append('div').attr('class', 'preset-list-button-wrap category');
89426
89427               function click() {
89428                 var isExpanded = select(this).classed('expanded');
89429                 var iconName = isExpanded ? _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward' : '#iD-icon-down';
89430                 select(this).classed('expanded', !isExpanded);
89431                 select(this).selectAll('div.label-inner svg.icon use').attr('href', iconName);
89432                 item.choose();
89433               }
89434
89435               var geometries = entityGeometries();
89436               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) {
89437                 // right arrow, expand the focused item
89438                 if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '←' : '→']) {
89439                   d3_event.preventDefault();
89440                   d3_event.stopPropagation(); // if the item isn't expanded
89441
89442                   if (!select(this).classed('expanded')) {
89443                     // toggle expansion (expand the item)
89444                     click.call(this, d3_event);
89445                   } // left arrow, collapse the focused item
89446
89447                 } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '→' : '←']) {
89448                   d3_event.preventDefault();
89449                   d3_event.stopPropagation(); // if the item is expanded
89450
89451                   if (select(this).classed('expanded')) {
89452                     // toggle expansion (collapse the item)
89453                     click.call(this, d3_event);
89454                   }
89455                 } else {
89456                   itemKeydown.call(this, d3_event);
89457                 }
89458               });
89459               var label = button.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
89460               label.append('div').attr('class', 'namepart').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward', 'inline')).append('span').html(function () {
89461                 return preset.nameLabel() + '&hellip;';
89462               });
89463               box = selection.append('div').attr('class', 'subgrid').style('max-height', '0px').style('opacity', 0);
89464               box.append('div').attr('class', 'arrow');
89465               sublist = box.append('div').attr('class', 'preset-list fillL3');
89466             }
89467
89468             item.choose = function () {
89469               if (!box || !sublist) return;
89470
89471               if (shown) {
89472                 shown = false;
89473                 box.transition().duration(200).style('opacity', '0').style('max-height', '0px').style('padding-bottom', '0px');
89474               } else {
89475                 shown = true;
89476                 var members = preset.members.matchAllGeometry(entityGeometries());
89477                 sublist.call(drawList, members);
89478                 box.transition().duration(200).style('opacity', '1').style('max-height', 200 + members.collection.length * 190 + 'px').style('padding-bottom', '10px');
89479               }
89480             };
89481
89482             item.preset = preset;
89483             return item;
89484           }
89485
89486           function PresetItem(preset) {
89487             function item(selection) {
89488               var wrap = selection.append('div').attr('class', 'preset-list-button-wrap');
89489               var geometries = entityGeometries();
89490               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);
89491               var label = button.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
89492               var nameparts = [preset.nameLabel(), preset.subtitleLabel()].filter(Boolean);
89493               label.selectAll('.namepart').data(nameparts).enter().append('div').attr('class', 'namepart').html(function (d) {
89494                 return d;
89495               });
89496               wrap.call(item.reference.button);
89497               selection.call(item.reference.body);
89498             }
89499
89500             item.choose = function () {
89501               if (select(this).classed('disabled')) return;
89502
89503               if (!context.inIntro()) {
89504                 _mainPresetIndex.setMostRecent(preset, entityGeometries()[0]);
89505               }
89506
89507               context.perform(function (graph) {
89508                 for (var i in _entityIDs) {
89509                   var entityID = _entityIDs[i];
89510                   var oldPreset = _mainPresetIndex.match(graph.entity(entityID), graph);
89511                   graph = actionChangePreset(entityID, oldPreset, preset)(graph);
89512                 }
89513
89514                 return graph;
89515               }, _t('operations.change_tags.annotation'));
89516               context.validator().validate(); // rerun validation
89517
89518               dispatch$1.call('choose', this, preset);
89519             };
89520
89521             item.help = function (d3_event) {
89522               d3_event.stopPropagation();
89523               item.reference.toggle();
89524             };
89525
89526             item.preset = preset;
89527             item.reference = uiTagReference(preset.reference());
89528             return item;
89529           }
89530
89531           function updateForFeatureHiddenState() {
89532             if (!_entityIDs.every(context.hasEntity)) return;
89533             var geometries = entityGeometries();
89534             var button = context.container().selectAll('.preset-list .preset-list-button'); // remove existing tooltips
89535
89536             button.call(uiTooltip().destroyAny);
89537             button.each(function (item, index) {
89538               var hiddenPresetFeaturesId;
89539
89540               for (var i in geometries) {
89541                 hiddenPresetFeaturesId = context.features().isHiddenPreset(item.preset, geometries[i]);
89542                 if (hiddenPresetFeaturesId) break;
89543               }
89544
89545               var isHiddenPreset = !context.inIntro() && !!hiddenPresetFeaturesId && (_currentPresets.length !== 1 || item.preset !== _currentPresets[0]);
89546               select(this).classed('disabled', isHiddenPreset);
89547
89548               if (isHiddenPreset) {
89549                 var isAutoHidden = context.features().autoHidden(hiddenPresetFeaturesId);
89550                 select(this).call(uiTooltip().title(_t.html('inspector.hidden_preset.' + (isAutoHidden ? 'zoom' : 'manual'), {
89551                   features: _t.html('feature.' + hiddenPresetFeaturesId + '.description')
89552                 })).placement(index < 2 ? 'bottom' : 'top'));
89553               }
89554             });
89555           }
89556
89557           presetList.autofocus = function (val) {
89558             if (!arguments.length) return _autofocus;
89559             _autofocus = val;
89560             return presetList;
89561           };
89562
89563           presetList.entityIDs = function (val) {
89564             if (!arguments.length) return _entityIDs;
89565             _entityIDs = val;
89566
89567             if (_entityIDs && _entityIDs.length) {
89568               var presets = _entityIDs.map(function (entityID) {
89569                 return _mainPresetIndex.match(context.entity(entityID), context.graph());
89570               });
89571
89572               presetList.presets(presets);
89573             }
89574
89575             return presetList;
89576           };
89577
89578           presetList.presets = function (val) {
89579             if (!arguments.length) return _currentPresets;
89580             _currentPresets = val;
89581             return presetList;
89582           };
89583
89584           function entityGeometries() {
89585             var counts = {};
89586
89587             for (var i in _entityIDs) {
89588               var entityID = _entityIDs[i];
89589               var entity = context.entity(entityID);
89590               var geometry = entity.geometry(context.graph()); // Treat entities on addr:interpolation lines as points, not vertices (#3241)
89591
89592               if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) {
89593                 geometry = 'point';
89594               }
89595
89596               if (!counts[geometry]) counts[geometry] = 0;
89597               counts[geometry] += 1;
89598             }
89599
89600             return Object.keys(counts).sort(function (geom1, geom2) {
89601               return counts[geom2] - counts[geom1];
89602             });
89603           }
89604
89605           function combinedEntityExtent() {
89606             return _entityIDs.reduce(function (extent, entityID) {
89607               var entity = context.graph().entity(entityID);
89608               return extent.extend(entity.extent(context.graph()));
89609             }, geoExtent());
89610           }
89611
89612           return utilRebind(presetList, dispatch$1, 'on');
89613         }
89614
89615         function uiInspector(context) {
89616           var presetList = uiPresetList(context);
89617           var entityEditor = uiEntityEditor(context);
89618           var wrap = select(null),
89619               presetPane = select(null),
89620               editorPane = select(null);
89621           var _state = 'select';
89622
89623           var _entityIDs;
89624
89625           var _newFeature = false;
89626
89627           function inspector(selection) {
89628             presetList.entityIDs(_entityIDs).autofocus(_newFeature).on('choose', inspector.setPreset).on('cancel', function () {
89629               inspector.setPreset();
89630             });
89631             entityEditor.state(_state).entityIDs(_entityIDs).on('choose', inspector.showList);
89632             wrap = selection.selectAll('.panewrap').data([0]);
89633             var enter = wrap.enter().append('div').attr('class', 'panewrap');
89634             enter.append('div').attr('class', 'preset-list-pane pane');
89635             enter.append('div').attr('class', 'entity-editor-pane pane');
89636             wrap = wrap.merge(enter);
89637             presetPane = wrap.selectAll('.preset-list-pane');
89638             editorPane = wrap.selectAll('.entity-editor-pane');
89639
89640             function shouldDefaultToPresetList() {
89641               // always show the inspector on hover
89642               if (_state !== 'select') return false; // can only change preset on single selection
89643
89644               if (_entityIDs.length !== 1) return false;
89645               var entityID = _entityIDs[0];
89646               var entity = context.hasEntity(entityID);
89647               if (!entity) return false; // default to inspector if there are already tags
89648
89649               if (entity.hasNonGeometryTags()) return false; // prompt to select preset if feature is new and untagged
89650
89651               if (_newFeature) return true; // all existing features except vertices should default to inspector
89652
89653               if (entity.geometry(context.graph()) !== 'vertex') return false; // show vertex relations if any
89654
89655               if (context.graph().parentRelations(entity).length) return false; // show vertex issues if there are any
89656
89657               if (context.validator().getEntityIssues(entityID).length) return false; // show turn retriction editor for junction vertices
89658
89659               if (entity.isHighwayIntersection(context.graph())) return false; // otherwise show preset list for uninteresting vertices
89660
89661               return true;
89662             }
89663
89664             if (shouldDefaultToPresetList()) {
89665               wrap.style('right', '-100%');
89666               editorPane.classed('hide', true);
89667               presetPane.classed('hide', false).call(presetList);
89668             } else {
89669               wrap.style('right', '0%');
89670               presetPane.classed('hide', true);
89671               editorPane.classed('hide', false).call(entityEditor);
89672             }
89673
89674             var footer = selection.selectAll('.footer').data([0]);
89675             footer = footer.enter().append('div').attr('class', 'footer').merge(footer);
89676             footer.call(uiViewOnOSM(context).what(context.hasEntity(_entityIDs.length === 1 && _entityIDs[0])));
89677           }
89678
89679           inspector.showList = function (presets) {
89680             presetPane.classed('hide', false);
89681             wrap.transition().styleTween('right', function () {
89682               return interpolate('0%', '-100%');
89683             }).on('end', function () {
89684               editorPane.classed('hide', true);
89685             });
89686
89687             if (presets) {
89688               presetList.presets(presets);
89689             }
89690
89691             presetPane.call(presetList.autofocus(true));
89692           };
89693
89694           inspector.setPreset = function (preset) {
89695             // upon setting multipolygon, go to the area preset list instead of the editor
89696             if (preset && preset.id === 'type/multipolygon') {
89697               presetPane.call(presetList.autofocus(true));
89698             } else {
89699               editorPane.classed('hide', false);
89700               wrap.transition().styleTween('right', function () {
89701                 return interpolate('-100%', '0%');
89702               }).on('end', function () {
89703                 presetPane.classed('hide', true);
89704               });
89705
89706               if (preset) {
89707                 entityEditor.presets([preset]);
89708               }
89709
89710               editorPane.call(entityEditor);
89711             }
89712           };
89713
89714           inspector.state = function (val) {
89715             if (!arguments.length) return _state;
89716             _state = val;
89717             entityEditor.state(_state); // remove any old field help overlay that might have gotten attached to the inspector
89718
89719             context.container().selectAll('.field-help-body').remove();
89720             return inspector;
89721           };
89722
89723           inspector.entityIDs = function (val) {
89724             if (!arguments.length) return _entityIDs;
89725             _entityIDs = val;
89726             return inspector;
89727           };
89728
89729           inspector.newFeature = function (val) {
89730             if (!arguments.length) return _newFeature;
89731             _newFeature = val;
89732             return inspector;
89733           };
89734
89735           return inspector;
89736         }
89737
89738         function uiSidebar(context) {
89739           var inspector = uiInspector(context);
89740           var dataEditor = uiDataEditor(context);
89741           var noteEditor = uiNoteEditor(context);
89742           var improveOsmEditor = uiImproveOsmEditor(context);
89743           var keepRightEditor = uiKeepRightEditor(context);
89744           var osmoseEditor = uiOsmoseEditor(context);
89745
89746           var _current;
89747
89748           var _wasData = false;
89749           var _wasNote = false;
89750           var _wasQaItem = false; // use pointer events on supported platforms; fallback to mouse events
89751
89752           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
89753
89754           function sidebar(selection) {
89755             var container = context.container();
89756             var minWidth = 240;
89757             var sidebarWidth;
89758             var containerWidth;
89759             var dragOffset; // Set the initial width constraints
89760
89761             selection.style('min-width', minWidth + 'px').style('max-width', '400px').style('width', '33.3333%');
89762             var resizer = selection.append('div').attr('class', 'sidebar-resizer').on(_pointerPrefix + 'down.sidebar-resizer', pointerdown);
89763             var downPointerId, lastClientX, containerLocGetter;
89764
89765             function pointerdown(d3_event) {
89766               if (downPointerId) return;
89767               if ('button' in d3_event && d3_event.button !== 0) return;
89768               downPointerId = d3_event.pointerId || 'mouse';
89769               lastClientX = d3_event.clientX;
89770               containerLocGetter = utilFastMouse(container.node()); // offset from edge of sidebar-resizer
89771
89772               dragOffset = utilFastMouse(resizer.node())(d3_event)[0] - 1;
89773               sidebarWidth = selection.node().getBoundingClientRect().width;
89774               containerWidth = container.node().getBoundingClientRect().width;
89775               var widthPct = sidebarWidth / containerWidth * 100;
89776               selection.style('width', widthPct + '%') // lock in current width
89777               .style('max-width', '85%'); // but allow larger widths
89778
89779               resizer.classed('dragging', true);
89780               select(window).on('touchmove.sidebar-resizer', function (d3_event) {
89781                 // disable page scrolling while resizing on touch input
89782                 d3_event.preventDefault();
89783               }, {
89784                 passive: false
89785               }).on(_pointerPrefix + 'move.sidebar-resizer', pointermove).on(_pointerPrefix + 'up.sidebar-resizer pointercancel.sidebar-resizer', pointerup);
89786             }
89787
89788             function pointermove(d3_event) {
89789               if (downPointerId !== (d3_event.pointerId || 'mouse')) return;
89790               d3_event.preventDefault();
89791               var dx = d3_event.clientX - lastClientX;
89792               lastClientX = d3_event.clientX;
89793               var isRTL = _mainLocalizer.textDirection() === 'rtl';
89794               var scaleX = isRTL ? 0 : 1;
89795               var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
89796               var x = containerLocGetter(d3_event)[0] - dragOffset;
89797               sidebarWidth = isRTL ? containerWidth - x : x;
89798               var isCollapsed = selection.classed('collapsed');
89799               var shouldCollapse = sidebarWidth < minWidth;
89800               selection.classed('collapsed', shouldCollapse);
89801
89802               if (shouldCollapse) {
89803                 if (!isCollapsed) {
89804                   selection.style(xMarginProperty, '-400px').style('width', '400px');
89805                   context.ui().onResize([(sidebarWidth - dx) * scaleX, 0]);
89806                 }
89807               } else {
89808                 var widthPct = sidebarWidth / containerWidth * 100;
89809                 selection.style(xMarginProperty, null).style('width', widthPct + '%');
89810
89811                 if (isCollapsed) {
89812                   context.ui().onResize([-sidebarWidth * scaleX, 0]);
89813                 } else {
89814                   context.ui().onResize([-dx * scaleX, 0]);
89815                 }
89816               }
89817             }
89818
89819             function pointerup(d3_event) {
89820               if (downPointerId !== (d3_event.pointerId || 'mouse')) return;
89821               downPointerId = null;
89822               resizer.classed('dragging', false);
89823               select(window).on('touchmove.sidebar-resizer', null).on(_pointerPrefix + 'move.sidebar-resizer', null).on(_pointerPrefix + 'up.sidebar-resizer pointercancel.sidebar-resizer', null);
89824             }
89825
89826             var featureListWrap = selection.append('div').attr('class', 'feature-list-pane').call(uiFeatureList(context));
89827             var inspectorWrap = selection.append('div').attr('class', 'inspector-hidden inspector-wrap');
89828
89829             var hoverModeSelect = function hoverModeSelect(targets) {
89830               context.container().selectAll('.feature-list-item button').classed('hover', false);
89831
89832               if (context.selectedIDs().length > 1 && targets && targets.length) {
89833                 var elements = context.container().selectAll('.feature-list-item button').filter(function (node) {
89834                   return targets.indexOf(node) !== -1;
89835                 });
89836
89837                 if (!elements.empty()) {
89838                   elements.classed('hover', true);
89839                 }
89840               }
89841             };
89842
89843             sidebar.hoverModeSelect = throttle(hoverModeSelect, 200);
89844
89845             function hover(targets) {
89846               var datum = targets && targets.length && targets[0];
89847
89848               if (datum && datum.__featurehash__) {
89849                 // hovering on data
89850                 _wasData = true;
89851                 sidebar.show(dataEditor.datum(datum));
89852                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
89853               } else if (datum instanceof osmNote) {
89854                 if (context.mode().id === 'drag-note') return;
89855                 _wasNote = true;
89856                 var osm = services.osm;
89857
89858                 if (osm) {
89859                   datum = osm.getNote(datum.id); // marker may contain stale data - get latest
89860                 }
89861
89862                 sidebar.show(noteEditor.note(datum));
89863                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
89864               } else if (datum instanceof QAItem) {
89865                 _wasQaItem = true;
89866                 var errService = services[datum.service];
89867
89868                 if (errService) {
89869                   // marker may contain stale data - get latest
89870                   datum = errService.getError(datum.id);
89871                 } // Currently only three possible services
89872
89873
89874                 var errEditor;
89875
89876                 if (datum.service === 'keepRight') {
89877                   errEditor = keepRightEditor;
89878                 } else if (datum.service === 'osmose') {
89879                   errEditor = osmoseEditor;
89880                 } else {
89881                   errEditor = improveOsmEditor;
89882                 }
89883
89884                 context.container().selectAll('.qaItem.' + datum.service).classed('hover', function (d) {
89885                   return d.id === datum.id;
89886                 });
89887                 sidebar.show(errEditor.error(datum));
89888                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
89889               } else if (!_current && datum instanceof osmEntity) {
89890                 featureListWrap.classed('inspector-hidden', true);
89891                 inspectorWrap.classed('inspector-hidden', false).classed('inspector-hover', true);
89892
89893                 if (!inspector.entityIDs() || !utilArrayIdentical(inspector.entityIDs(), [datum.id]) || inspector.state() !== 'hover') {
89894                   inspector.state('hover').entityIDs([datum.id]).newFeature(false);
89895                   inspectorWrap.call(inspector);
89896                 }
89897               } else if (!_current) {
89898                 featureListWrap.classed('inspector-hidden', false);
89899                 inspectorWrap.classed('inspector-hidden', true);
89900                 inspector.state('hide');
89901               } else if (_wasData || _wasNote || _wasQaItem) {
89902                 _wasNote = false;
89903                 _wasData = false;
89904                 _wasQaItem = false;
89905                 context.container().selectAll('.note').classed('hover', false);
89906                 context.container().selectAll('.qaItem').classed('hover', false);
89907                 sidebar.hide();
89908               }
89909             }
89910
89911             sidebar.hover = throttle(hover, 200);
89912
89913             sidebar.intersects = function (extent) {
89914               var rect = selection.node().getBoundingClientRect();
89915               return extent.intersects([context.projection.invert([0, rect.height]), context.projection.invert([rect.width, 0])]);
89916             };
89917
89918             sidebar.select = function (ids, newFeature) {
89919               sidebar.hide();
89920
89921               if (ids && ids.length) {
89922                 var entity = ids.length === 1 && context.entity(ids[0]);
89923
89924                 if (entity && newFeature && selection.classed('collapsed')) {
89925                   // uncollapse the sidebar
89926                   var extent = entity.extent(context.graph());
89927                   sidebar.expand(sidebar.intersects(extent));
89928                 }
89929
89930                 featureListWrap.classed('inspector-hidden', true);
89931                 inspectorWrap.classed('inspector-hidden', false).classed('inspector-hover', false); // reload the UI even if the ids are the same since the entities
89932                 // themselves may have changed
89933
89934                 inspector.state('select').entityIDs(ids).newFeature(newFeature);
89935                 inspectorWrap.call(inspector);
89936               } else {
89937                 inspector.state('hide');
89938               }
89939             };
89940
89941             sidebar.showPresetList = function () {
89942               inspector.showList();
89943             };
89944
89945             sidebar.show = function (component, element) {
89946               featureListWrap.classed('inspector-hidden', true);
89947               inspectorWrap.classed('inspector-hidden', true);
89948               if (_current) _current.remove();
89949               _current = selection.append('div').attr('class', 'sidebar-component').call(component, element);
89950             };
89951
89952             sidebar.hide = function () {
89953               featureListWrap.classed('inspector-hidden', false);
89954               inspectorWrap.classed('inspector-hidden', true);
89955               if (_current) _current.remove();
89956               _current = null;
89957             };
89958
89959             sidebar.expand = function (moveMap) {
89960               if (selection.classed('collapsed')) {
89961                 sidebar.toggle(moveMap);
89962               }
89963             };
89964
89965             sidebar.collapse = function (moveMap) {
89966               if (!selection.classed('collapsed')) {
89967                 sidebar.toggle(moveMap);
89968               }
89969             };
89970
89971             sidebar.toggle = function (moveMap) {
89972               // Don't allow sidebar to toggle when the user is in the walkthrough.
89973               if (context.inIntro()) return;
89974               var isCollapsed = selection.classed('collapsed');
89975               var isCollapsing = !isCollapsed;
89976               var isRTL = _mainLocalizer.textDirection() === 'rtl';
89977               var scaleX = isRTL ? 0 : 1;
89978               var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
89979               sidebarWidth = selection.node().getBoundingClientRect().width; // switch from % to px
89980
89981               selection.style('width', sidebarWidth + 'px');
89982               var startMargin, endMargin, lastMargin;
89983
89984               if (isCollapsing) {
89985                 startMargin = lastMargin = 0;
89986                 endMargin = -sidebarWidth;
89987               } else {
89988                 startMargin = lastMargin = -sidebarWidth;
89989                 endMargin = 0;
89990               }
89991
89992               if (!isCollapsing) {
89993                 // unhide the sidebar's content before it transitions onscreen
89994                 selection.classed('collapsed', isCollapsing);
89995               }
89996
89997               selection.transition().style(xMarginProperty, endMargin + 'px').tween('panner', function () {
89998                 var i = d3_interpolateNumber(startMargin, endMargin);
89999                 return function (t) {
90000                   var dx = lastMargin - Math.round(i(t));
90001                   lastMargin = lastMargin - dx;
90002                   context.ui().onResize(moveMap ? undefined : [dx * scaleX, 0]);
90003                 };
90004               }).on('end', function () {
90005                 if (isCollapsing) {
90006                   // hide the sidebar's content after it transitions offscreen
90007                   selection.classed('collapsed', isCollapsing);
90008                 } // switch back from px to %
90009
90010
90011                 if (!isCollapsing) {
90012                   var containerWidth = container.node().getBoundingClientRect().width;
90013                   var widthPct = sidebarWidth / containerWidth * 100;
90014                   selection.style(xMarginProperty, null).style('width', widthPct + '%');
90015                 }
90016               });
90017             }; // toggle the sidebar collapse when double-clicking the resizer
90018
90019
90020             resizer.on('dblclick', function (d3_event) {
90021               d3_event.preventDefault();
90022
90023               if (d3_event.sourceEvent) {
90024                 d3_event.sourceEvent.preventDefault();
90025               }
90026
90027               sidebar.toggle();
90028             }); // ensure hover sidebar is closed when zooming out beyond editable zoom
90029
90030             context.map().on('crossEditableZoom.sidebar', function (within) {
90031               if (!within && !selection.select('.inspector-hover').empty()) {
90032                 hover([]);
90033               }
90034             });
90035           }
90036
90037           sidebar.showPresetList = function () {};
90038
90039           sidebar.hover = function () {};
90040
90041           sidebar.hover.cancel = function () {};
90042
90043           sidebar.intersects = function () {};
90044
90045           sidebar.select = function () {};
90046
90047           sidebar.show = function () {};
90048
90049           sidebar.hide = function () {};
90050
90051           sidebar.expand = function () {};
90052
90053           sidebar.collapse = function () {};
90054
90055           sidebar.toggle = function () {};
90056
90057           return sidebar;
90058         }
90059
90060         function uiSourceSwitch(context) {
90061           var keys;
90062
90063           function click(d3_event) {
90064             d3_event.preventDefault();
90065             var osm = context.connection();
90066             if (!osm) return;
90067             if (context.inIntro()) return;
90068             if (context.history().hasChanges() && !window.confirm(_t('source_switch.lose_changes'))) return;
90069             var isLive = select(this).classed('live');
90070             isLive = !isLive;
90071             context.enter(modeBrowse(context));
90072             context.history().clearSaved(); // remove saved history
90073
90074             context.flush(); // remove stored data
90075
90076             select(this).html(isLive ? _t.html('source_switch.live') : _t.html('source_switch.dev')).classed('live', isLive).classed('chip', isLive);
90077             osm["switch"](isLive ? keys[0] : keys[1]); // switch connection (warning: dispatches 'change' event)
90078           }
90079
90080           var sourceSwitch = function sourceSwitch(selection) {
90081             selection.append('a').attr('href', '#').html(_t.html('source_switch.live')).attr('class', 'live chip').on('click', click);
90082           };
90083
90084           sourceSwitch.keys = function (_) {
90085             if (!arguments.length) return keys;
90086             keys = _;
90087             return sourceSwitch;
90088           };
90089
90090           return sourceSwitch;
90091         }
90092
90093         function uiSpinner(context) {
90094           var osm = context.connection();
90095           return function (selection) {
90096             var img = selection.append('img').attr('src', context.imagePath('loader-black.gif')).style('opacity', 0);
90097
90098             if (osm) {
90099               osm.on('loading.spinner', function () {
90100                 img.transition().style('opacity', 1);
90101               }).on('loaded.spinner', function () {
90102                 img.transition().style('opacity', 0);
90103               });
90104             }
90105           };
90106         }
90107
90108         function uiSplash(context) {
90109           return function (selection) {
90110             // Exception - if there are restorable changes, skip this splash screen.
90111             // This is because we currently only support one `uiModal` at a time
90112             //  and we need to show them `uiRestore`` instead of this one.
90113             if (context.history().hasRestorableChanges()) return; // If user has not seen this version of the privacy policy, show the splash again.
90114
90115             var updateMessage = '';
90116             var sawPrivacyVersion = corePreferences('sawPrivacyVersion');
90117             var showSplash = !corePreferences('sawSplash');
90118
90119             if (sawPrivacyVersion !== context.privacyVersion) {
90120               updateMessage = _t('splash.privacy_update');
90121               showSplash = true;
90122             }
90123
90124             if (!showSplash) return;
90125             corePreferences('sawSplash', true);
90126             corePreferences('sawPrivacyVersion', context.privacyVersion); // fetch intro graph data now, while user is looking at the splash screen
90127
90128             _mainFileFetcher.get('intro_graph');
90129             var modalSelection = uiModal(selection);
90130             modalSelection.select('.modal').attr('class', 'modal-splash modal');
90131             var introModal = modalSelection.select('.content').append('div').attr('class', 'fillL');
90132             introModal.append('div').attr('class', 'modal-section').append('h3').html(_t.html('splash.welcome'));
90133             var modalSection = introModal.append('div').attr('class', 'modal-section');
90134             modalSection.append('p').html(_t.html('splash.text', {
90135               version: context.version,
90136               website: '<a target="_blank" href="http://ideditor.blog/">ideditor.blog</a>',
90137               github: '<a target="_blank" href="https://github.com/openstreetmap/iD">github.com</a>'
90138             }));
90139             modalSection.append('p').html(_t.html('splash.privacy', {
90140               updateMessage: updateMessage,
90141               privacyLink: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/release/PRIVACY.md">' + _t('splash.privacy_policy') + '</a>'
90142             }));
90143             var buttonWrap = introModal.append('div').attr('class', 'modal-actions');
90144             var walkthrough = buttonWrap.append('button').attr('class', 'walkthrough').on('click', function () {
90145               context.container().call(uiIntro(context));
90146               modalSelection.close();
90147             });
90148             walkthrough.append('svg').attr('class', 'logo logo-walkthrough').append('use').attr('xlink:href', '#iD-logo-walkthrough');
90149             walkthrough.append('div').html(_t.html('splash.walkthrough'));
90150             var startEditing = buttonWrap.append('button').attr('class', 'start-editing').on('click', modalSelection.close);
90151             startEditing.append('svg').attr('class', 'logo logo-features').append('use').attr('xlink:href', '#iD-logo-features');
90152             startEditing.append('div').html(_t.html('splash.start'));
90153             modalSelection.select('button.close').attr('class', 'hide');
90154           };
90155         }
90156
90157         function uiStatus(context) {
90158           var osm = context.connection();
90159           return function (selection) {
90160             if (!osm) return;
90161
90162             function update(err, apiStatus) {
90163               selection.html('');
90164
90165               if (err) {
90166                 if (apiStatus === 'connectionSwitched') {
90167                   // if the connection was just switched, we can't rely on
90168                   // the status (we're getting the status of the previous api)
90169                   return;
90170                 } else if (apiStatus === 'rateLimited') {
90171                   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) {
90172                     d3_event.preventDefault();
90173                     osm.authenticate();
90174                   });
90175                 } else {
90176                   // don't allow retrying too rapidly
90177                   var throttledRetry = throttle(function () {
90178                     // try loading the visible tiles
90179                     context.loadTiles(context.projection); // manually reload the status too in case all visible tiles were already loaded
90180
90181                     osm.reloadApiStatus();
90182                   }, 2000); // eslint-disable-next-line no-warning-comments
90183                   // TODO: nice messages for different error types
90184
90185
90186                   selection.html(_t.html('osm_api_status.message.error') + ' ').append('a').attr('href', '#') // let the user manually retry their connection directly
90187                   .html(_t.html('osm_api_status.retry')).on('click.retry', function (d3_event) {
90188                     d3_event.preventDefault();
90189                     throttledRetry();
90190                   });
90191                 }
90192               } else if (apiStatus === 'readonly') {
90193                 selection.html(_t.html('osm_api_status.message.readonly'));
90194               } else if (apiStatus === 'offline') {
90195                 selection.html(_t.html('osm_api_status.message.offline'));
90196               }
90197
90198               selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
90199             }
90200
90201             osm.on('apiStatusChange.uiStatus', update); // reload the status periodically regardless of other factors
90202
90203             window.setInterval(function () {
90204               osm.reloadApiStatus();
90205             }, 90000); // load the initial status in case no OSM data was loaded yet
90206
90207             osm.reloadApiStatus();
90208           };
90209         }
90210
90211         function modeDrawArea(context, wayID, startGraph, button) {
90212           var mode = {
90213             button: button,
90214             id: 'draw-area'
90215           };
90216           var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on('rejectedSelfIntersection.modeDrawArea', function () {
90217             context.ui().flash.iconName('#iD-icon-no').label(_t('self_intersection.error.areas'))();
90218           });
90219           mode.wayID = wayID;
90220
90221           mode.enter = function () {
90222             context.install(behavior);
90223           };
90224
90225           mode.exit = function () {
90226             context.uninstall(behavior);
90227           };
90228
90229           mode.selectedIDs = function () {
90230             return [wayID];
90231           };
90232
90233           mode.activeID = function () {
90234             return behavior && behavior.activeID() || [];
90235           };
90236
90237           return mode;
90238         }
90239
90240         function modeAddArea(context, mode) {
90241           mode.id = 'add-area';
90242           var behavior = behaviorAddWay(context).on('start', start).on('startFromWay', startFromWay).on('startFromNode', startFromNode);
90243           var defaultTags = {
90244             area: 'yes'
90245           };
90246           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'area');
90247
90248           function actionClose(wayId) {
90249             return function (graph) {
90250               return graph.replace(graph.entity(wayId).close());
90251             };
90252           }
90253
90254           function start(loc) {
90255             var startGraph = context.graph();
90256             var node = osmNode({
90257               loc: loc
90258             });
90259             var way = osmWay({
90260               tags: defaultTags
90261             });
90262             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id));
90263             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
90264           }
90265
90266           function startFromWay(loc, edge) {
90267             var startGraph = context.graph();
90268             var node = osmNode({
90269               loc: loc
90270             });
90271             var way = osmWay({
90272               tags: defaultTags
90273             });
90274             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id), actionAddMidpoint({
90275               loc: loc,
90276               edge: edge
90277             }, node));
90278             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
90279           }
90280
90281           function startFromNode(node) {
90282             var startGraph = context.graph();
90283             var way = osmWay({
90284               tags: defaultTags
90285             });
90286             context.perform(actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id));
90287             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
90288           }
90289
90290           mode.enter = function () {
90291             context.install(behavior);
90292           };
90293
90294           mode.exit = function () {
90295             context.uninstall(behavior);
90296           };
90297
90298           return mode;
90299         }
90300
90301         function modeAddLine(context, mode) {
90302           mode.id = 'add-line';
90303           var behavior = behaviorAddWay(context).on('start', start).on('startFromWay', startFromWay).on('startFromNode', startFromNode);
90304           var defaultTags = {};
90305           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'line');
90306
90307           function start(loc) {
90308             var startGraph = context.graph();
90309             var node = osmNode({
90310               loc: loc
90311             });
90312             var way = osmWay({
90313               tags: defaultTags
90314             });
90315             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id));
90316             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
90317           }
90318
90319           function startFromWay(loc, edge) {
90320             var startGraph = context.graph();
90321             var node = osmNode({
90322               loc: loc
90323             });
90324             var way = osmWay({
90325               tags: defaultTags
90326             });
90327             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionAddMidpoint({
90328               loc: loc,
90329               edge: edge
90330             }, node));
90331             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
90332           }
90333
90334           function startFromNode(node) {
90335             var startGraph = context.graph();
90336             var way = osmWay({
90337               tags: defaultTags
90338             });
90339             context.perform(actionAddEntity(way), actionAddVertex(way.id, node.id));
90340             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
90341           }
90342
90343           mode.enter = function () {
90344             context.install(behavior);
90345           };
90346
90347           mode.exit = function () {
90348             context.uninstall(behavior);
90349           };
90350
90351           return mode;
90352         }
90353
90354         function modeAddPoint(context, mode) {
90355           mode.id = 'add-point';
90356           var behavior = behaviorDraw(context).on('click', add).on('clickWay', addWay).on('clickNode', addNode).on('cancel', cancel).on('finish', cancel);
90357           var defaultTags = {};
90358           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'point');
90359
90360           function add(loc) {
90361             var node = osmNode({
90362               loc: loc,
90363               tags: defaultTags
90364             });
90365             context.perform(actionAddEntity(node), _t('operations.add.annotation.point'));
90366             enterSelectMode(node);
90367           }
90368
90369           function addWay(loc, edge) {
90370             var node = osmNode({
90371               tags: defaultTags
90372             });
90373             context.perform(actionAddMidpoint({
90374               loc: loc,
90375               edge: edge
90376             }, node), _t('operations.add.annotation.vertex'));
90377             enterSelectMode(node);
90378           }
90379
90380           function enterSelectMode(node) {
90381             context.enter(modeSelect(context, [node.id]).newFeature(true));
90382           }
90383
90384           function addNode(node) {
90385             if (Object.keys(defaultTags).length === 0) {
90386               enterSelectMode(node);
90387               return;
90388             }
90389
90390             var tags = Object.assign({}, node.tags); // shallow copy
90391
90392             for (var key in defaultTags) {
90393               tags[key] = defaultTags[key];
90394             }
90395
90396             context.perform(actionChangeTags(node.id, tags), _t('operations.add.annotation.point'));
90397             enterSelectMode(node);
90398           }
90399
90400           function cancel() {
90401             context.enter(modeBrowse(context));
90402           }
90403
90404           mode.enter = function () {
90405             context.install(behavior);
90406           };
90407
90408           mode.exit = function () {
90409             context.uninstall(behavior);
90410           };
90411
90412           return mode;
90413         }
90414
90415         function modeAddNote(context) {
90416           var mode = {
90417             id: 'add-note',
90418             button: 'note',
90419             description: _t.html('modes.add_note.description'),
90420             key: _t('modes.add_note.key')
90421           };
90422           var behavior = behaviorDraw(context).on('click', add).on('cancel', cancel).on('finish', cancel);
90423
90424           function add(loc) {
90425             var osm = services.osm;
90426             if (!osm) return;
90427             var note = osmNote({
90428               loc: loc,
90429               status: 'open',
90430               comments: []
90431             });
90432             osm.replaceNote(note); // force a reraw (there is no history change that would otherwise do this)
90433
90434             context.map().pan([0, 0]);
90435             context.selectedNoteID(note.id).enter(modeSelectNote(context, note.id).newFeature(true));
90436           }
90437
90438           function cancel() {
90439             context.enter(modeBrowse(context));
90440           }
90441
90442           mode.enter = function () {
90443             context.install(behavior);
90444           };
90445
90446           mode.exit = function () {
90447             context.uninstall(behavior);
90448           };
90449
90450           return mode;
90451         }
90452
90453         function uiConflicts(context) {
90454           var dispatch$1 = dispatch('cancel', 'save');
90455           var keybinding = utilKeybinding('conflicts');
90456
90457           var _origChanges;
90458
90459           var _conflictList;
90460
90461           var _shownConflictIndex;
90462
90463           function keybindingOn() {
90464             select(document).call(keybinding.on('⎋', cancel, true));
90465           }
90466
90467           function keybindingOff() {
90468             select(document).call(keybinding.unbind);
90469           }
90470
90471           function tryAgain() {
90472             keybindingOff();
90473             dispatch$1.call('save');
90474           }
90475
90476           function cancel() {
90477             keybindingOff();
90478             dispatch$1.call('cancel');
90479           }
90480
90481           function conflicts(selection) {
90482             keybindingOn();
90483             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
90484             headerEnter.append('button').attr('class', 'fr').on('click', cancel).call(svgIcon('#iD-icon-close'));
90485             headerEnter.append('h3').html(_t.html('save.conflict.header'));
90486             var bodyEnter = selection.selectAll('.body').data([0]).enter().append('div').attr('class', 'body fillL');
90487             var conflictsHelpEnter = bodyEnter.append('div').attr('class', 'conflicts-help').html(_t.html('save.conflict.help')); // Download changes link
90488
90489             var detected = utilDetect();
90490             var changeset = new osmChangeset();
90491             delete changeset.id; // Export without changeset_id
90492
90493             var data = JXON.stringify(changeset.osmChangeJXON(_origChanges));
90494             var blob = new Blob([data], {
90495               type: 'text/xml;charset=utf-8;'
90496             });
90497             var fileName = 'changes.osc';
90498             var linkEnter = conflictsHelpEnter.selectAll('.download-changes').append('a').attr('class', 'download-changes');
90499
90500             if (detected.download) {
90501               // All except IE11 and Edge
90502               linkEnter // download the data as a file
90503               .attr('href', window.URL.createObjectURL(blob)).attr('download', fileName);
90504             } else {
90505               // IE11 and Edge
90506               linkEnter // open data uri in a new tab
90507               .attr('target', '_blank').on('click.download', function () {
90508                 navigator.msSaveBlob(blob, fileName);
90509               });
90510             }
90511
90512             linkEnter.call(svgIcon('#iD-icon-load', 'inline')).append('span').html(_t.html('save.conflict.download_changes'));
90513             bodyEnter.append('div').attr('class', 'conflict-container fillL3').call(showConflict, 0);
90514             bodyEnter.append('div').attr('class', 'conflicts-done').attr('opacity', 0).style('display', 'none').html(_t.html('save.conflict.done'));
90515             var buttonsEnter = bodyEnter.append('div').attr('class', 'buttons col12 joined conflicts-buttons');
90516             buttonsEnter.append('button').attr('disabled', _conflictList.length > 1).attr('class', 'action conflicts-button col6').html(_t.html('save.title')).on('click.try_again', tryAgain);
90517             buttonsEnter.append('button').attr('class', 'secondary-action conflicts-button col6').html(_t.html('confirm.cancel')).on('click.cancel', cancel);
90518           }
90519
90520           function showConflict(selection, index) {
90521             index = utilWrap(index, _conflictList.length);
90522             _shownConflictIndex = index;
90523             var parent = select(selection.node().parentNode); // enable save button if this is the last conflict being reviewed..
90524
90525             if (index === _conflictList.length - 1) {
90526               window.setTimeout(function () {
90527                 parent.select('.conflicts-button').attr('disabled', null);
90528                 parent.select('.conflicts-done').transition().attr('opacity', 1).style('display', 'block');
90529               }, 250);
90530             }
90531
90532             var conflict = selection.selectAll('.conflict').data([_conflictList[index]]);
90533             conflict.exit().remove();
90534             var conflictEnter = conflict.enter().append('div').attr('class', 'conflict');
90535             conflictEnter.append('h4').attr('class', 'conflict-count').html(_t.html('save.conflict.count', {
90536               num: index + 1,
90537               total: _conflictList.length
90538             }));
90539             conflictEnter.append('a').attr('class', 'conflict-description').attr('href', '#').html(function (d) {
90540               return d.name;
90541             }).on('click', function (d3_event, d) {
90542               d3_event.preventDefault();
90543               zoomToEntity(d.id);
90544             });
90545             var details = conflictEnter.append('div').attr('class', 'conflict-detail-container');
90546             details.append('ul').attr('class', 'conflict-detail-list').selectAll('li').data(function (d) {
90547               return d.details || [];
90548             }).enter().append('li').attr('class', 'conflict-detail-item').html(function (d) {
90549               return d;
90550             });
90551             details.append('div').attr('class', 'conflict-choices').call(addChoices);
90552             details.append('div').attr('class', 'conflict-nav-buttons joined cf').selectAll('button').data(['previous', 'next']).enter().append('button').html(function (d) {
90553               return _t.html('save.conflict.' + d);
90554             }).attr('class', 'conflict-nav-button action col6').attr('disabled', function (d, i) {
90555               return i === 0 && index === 0 || i === 1 && index === _conflictList.length - 1 || null;
90556             }).on('click', function (d3_event, d) {
90557               d3_event.preventDefault();
90558               var container = parent.selectAll('.conflict-container');
90559               var sign = d === 'previous' ? -1 : 1;
90560               container.selectAll('.conflict').remove();
90561               container.call(showConflict, index + sign);
90562             });
90563           }
90564
90565           function addChoices(selection) {
90566             var choices = selection.append('ul').attr('class', 'layer-list').selectAll('li').data(function (d) {
90567               return d.choices || [];
90568             }); // enter
90569
90570             var choicesEnter = choices.enter().append('li').attr('class', 'layer');
90571             var labelEnter = choicesEnter.append('label');
90572             labelEnter.append('input').attr('type', 'radio').attr('name', function (d) {
90573               return d.id;
90574             }).on('change', function (d3_event, d) {
90575               var ul = this.parentNode.parentNode.parentNode;
90576               ul.__data__.chosen = d.id;
90577               choose(d3_event, ul, d);
90578             });
90579             labelEnter.append('span').html(function (d) {
90580               return d.text;
90581             }); // update
90582
90583             choicesEnter.merge(choices).each(function (d) {
90584               var ul = this.parentNode;
90585
90586               if (ul.__data__.chosen === d.id) {
90587                 choose(null, ul, d);
90588               }
90589             });
90590           }
90591
90592           function choose(d3_event, ul, datum) {
90593             if (d3_event) d3_event.preventDefault();
90594             select(ul).selectAll('li').classed('active', function (d) {
90595               return d === datum;
90596             }).selectAll('input').property('checked', function (d) {
90597               return d === datum;
90598             });
90599             var extent = geoExtent();
90600             var entity;
90601             entity = context.graph().hasEntity(datum.id);
90602             if (entity) extent._extend(entity.extent(context.graph()));
90603             datum.action();
90604             entity = context.graph().hasEntity(datum.id);
90605             if (entity) extent._extend(entity.extent(context.graph()));
90606             zoomToEntity(datum.id, extent);
90607           }
90608
90609           function zoomToEntity(id, extent) {
90610             context.surface().selectAll('.hover').classed('hover', false);
90611             var entity = context.graph().hasEntity(id);
90612
90613             if (entity) {
90614               if (extent) {
90615                 context.map().trimmedExtent(extent);
90616               } else {
90617                 context.map().zoomToEase(entity);
90618               }
90619
90620               context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed('hover', true);
90621             }
90622           } // The conflict list should be an array of objects like:
90623           // {
90624           //     id: id,
90625           //     name: entityName(local),
90626           //     details: merge.conflicts(),
90627           //     chosen: 1,
90628           //     choices: [
90629           //         choice(id, keepMine, forceLocal),
90630           //         choice(id, keepTheirs, forceRemote)
90631           //     ]
90632           // }
90633
90634
90635           conflicts.conflictList = function (_) {
90636             if (!arguments.length) return _conflictList;
90637             _conflictList = _;
90638             return conflicts;
90639           };
90640
90641           conflicts.origChanges = function (_) {
90642             if (!arguments.length) return _origChanges;
90643             _origChanges = _;
90644             return conflicts;
90645           };
90646
90647           conflicts.shownEntityIds = function () {
90648             if (_conflictList && typeof _shownConflictIndex === 'number') {
90649               return [_conflictList[_shownConflictIndex].id];
90650             }
90651
90652             return [];
90653           };
90654
90655           return utilRebind(conflicts, dispatch$1, 'on');
90656         }
90657
90658         function uiConfirm(selection) {
90659           var modalSelection = uiModal(selection);
90660           modalSelection.select('.modal').classed('modal-alert', true);
90661           var section = modalSelection.select('.content');
90662           section.append('div').attr('class', 'modal-section header');
90663           section.append('div').attr('class', 'modal-section message-text');
90664           var buttons = section.append('div').attr('class', 'modal-section buttons cf');
90665
90666           modalSelection.okButton = function () {
90667             buttons.append('button').attr('class', 'button ok-button action').on('click.confirm', function () {
90668               modalSelection.remove();
90669             }).html(_t.html('confirm.okay')).node().focus();
90670             return modalSelection;
90671           };
90672
90673           return modalSelection;
90674         }
90675
90676         function uiChangesetEditor(context) {
90677           var dispatch$1 = dispatch('change');
90678           var formFields = uiFormFields(context);
90679           var commentCombo = uiCombobox(context, 'comment').caseSensitive(true);
90680
90681           var _fieldsArr;
90682
90683           var _tags;
90684
90685           var _changesetID;
90686
90687           function changesetEditor(selection) {
90688             render(selection);
90689           }
90690
90691           function render(selection) {
90692             var initial = false;
90693
90694             if (!_fieldsArr) {
90695               initial = true;
90696               var presets = _mainPresetIndex;
90697               _fieldsArr = [uiField(context, presets.field('comment'), null, {
90698                 show: true,
90699                 revert: false
90700               }), uiField(context, presets.field('source'), null, {
90701                 show: false,
90702                 revert: false
90703               }), uiField(context, presets.field('hashtags'), null, {
90704                 show: false,
90705                 revert: false
90706               })];
90707
90708               _fieldsArr.forEach(function (field) {
90709                 field.on('change', function (t, onInput) {
90710                   dispatch$1.call('change', field, undefined, t, onInput);
90711                 });
90712               });
90713             }
90714
90715             _fieldsArr.forEach(function (field) {
90716               field.tags(_tags);
90717             });
90718
90719             selection.call(formFields.fieldsArr(_fieldsArr));
90720
90721             if (initial) {
90722               var commentField = selection.select('.form-field-comment textarea');
90723               var commentNode = commentField.node();
90724
90725               if (commentNode) {
90726                 commentNode.focus();
90727                 commentNode.select();
90728               } // trigger a 'blur' event so that comment field can be cleaned
90729               // and checked for hashtags, even if retrieved from localstorage
90730
90731
90732               utilTriggerEvent(commentField, 'blur');
90733               var osm = context.connection();
90734
90735               if (osm) {
90736                 osm.userChangesets(function (err, changesets) {
90737                   if (err) return;
90738                   var comments = changesets.map(function (changeset) {
90739                     var comment = changeset.tags.comment;
90740                     return comment ? {
90741                       title: comment,
90742                       value: comment
90743                     } : null;
90744                   }).filter(Boolean);
90745                   commentField.call(commentCombo.data(utilArrayUniqBy(comments, 'title')));
90746                 });
90747               }
90748             } // Add warning if comment mentions Google
90749
90750
90751             var hasGoogle = _tags.comment.match(/google/i);
90752
90753             var commentWarning = selection.select('.form-field-comment').selectAll('.comment-warning').data(hasGoogle ? [0] : []);
90754             commentWarning.exit().transition().duration(200).style('opacity', 0).remove();
90755             var commentEnter = commentWarning.enter().insert('div', '.tag-reference-body').attr('class', 'field-warning comment-warning').style('opacity', 0);
90756             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'));
90757             commentEnter.transition().duration(200).style('opacity', 1);
90758           }
90759
90760           changesetEditor.tags = function (_) {
90761             if (!arguments.length) return _tags;
90762             _tags = _; // Don't reset _fieldsArr here.
90763
90764             return changesetEditor;
90765           };
90766
90767           changesetEditor.changesetID = function (_) {
90768             if (!arguments.length) return _changesetID;
90769             if (_changesetID === _) return changesetEditor;
90770             _changesetID = _;
90771             _fieldsArr = null;
90772             return changesetEditor;
90773           };
90774
90775           return utilRebind(changesetEditor, dispatch$1, 'on');
90776         }
90777
90778         function uiSectionChanges(context) {
90779           var detected = utilDetect();
90780           var _discardTags = {};
90781           _mainFileFetcher.get('discarded').then(function (d) {
90782             _discardTags = d;
90783           })["catch"](function () {
90784             /* ignore */
90785           });
90786           var section = uiSection('changes-list', context).label(function () {
90787             var history = context.history();
90788             var summary = history.difference().summary();
90789             return _t('inspector.title_count', {
90790               title: _t.html('commit.changes'),
90791               count: summary.length
90792             });
90793           }).disclosureContent(renderDisclosureContent);
90794
90795           function renderDisclosureContent(selection) {
90796             var history = context.history();
90797             var summary = history.difference().summary();
90798             var container = selection.selectAll('.commit-section').data([0]);
90799             var containerEnter = container.enter().append('div').attr('class', 'commit-section');
90800             containerEnter.append('ul').attr('class', 'changeset-list');
90801             container = containerEnter.merge(container);
90802             var items = container.select('ul').selectAll('li').data(summary);
90803             var itemsEnter = items.enter().append('li').attr('class', 'change-item');
90804             var buttons = itemsEnter.append('button').on('mouseover', mouseover).on('mouseout', mouseout).on('click', click);
90805             buttons.each(function (d) {
90806               select(this).call(svgIcon('#iD-icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
90807             });
90808             buttons.append('span').attr('class', 'change-type').html(function (d) {
90809               return _t.html('commit.' + d.changeType) + ' ';
90810             });
90811             buttons.append('strong').attr('class', 'entity-type').html(function (d) {
90812               var matched = _mainPresetIndex.match(d.entity, d.graph);
90813               return matched && matched.name() || utilDisplayType(d.entity.id);
90814             });
90815             buttons.append('span').attr('class', 'entity-name').html(function (d) {
90816               var name = utilDisplayName(d.entity) || '',
90817                   string = '';
90818
90819               if (name !== '') {
90820                 string += ':';
90821               }
90822
90823               return string += ' ' + name;
90824             });
90825             items = itemsEnter.merge(items); // Download changeset link
90826
90827             var changeset = new osmChangeset().update({
90828               id: undefined
90829             });
90830             var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
90831             delete changeset.id; // Export without chnageset_id
90832
90833             var data = JXON.stringify(changeset.osmChangeJXON(changes));
90834             var blob = new Blob([data], {
90835               type: 'text/xml;charset=utf-8;'
90836             });
90837             var fileName = 'changes.osc';
90838             var linkEnter = container.selectAll('.download-changes').data([0]).enter().append('a').attr('class', 'download-changes');
90839
90840             if (detected.download) {
90841               // All except IE11 and Edge
90842               linkEnter // download the data as a file
90843               .attr('href', window.URL.createObjectURL(blob)).attr('download', fileName);
90844             } else {
90845               // IE11 and Edge
90846               linkEnter // open data uri in a new tab
90847               .attr('target', '_blank').on('click.download', function () {
90848                 navigator.msSaveBlob(blob, fileName);
90849               });
90850             }
90851
90852             linkEnter.call(svgIcon('#iD-icon-load', 'inline')).append('span').html(_t.html('commit.download_changes'));
90853
90854             function mouseover(d) {
90855               if (d.entity) {
90856                 context.surface().selectAll(utilEntityOrMemberSelector([d.entity.id], context.graph())).classed('hover', true);
90857               }
90858             }
90859
90860             function mouseout() {
90861               context.surface().selectAll('.hover').classed('hover', false);
90862             }
90863
90864             function click(d3_event, change) {
90865               if (change.changeType !== 'deleted') {
90866                 var entity = change.entity;
90867                 context.map().zoomToEase(entity);
90868                 context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed('hover', true);
90869               }
90870             }
90871           }
90872
90873           return section;
90874         }
90875
90876         function uiCommitWarnings(context) {
90877           function commitWarnings(selection) {
90878             var issuesBySeverity = context.validator().getIssuesBySeverity({
90879               what: 'edited',
90880               where: 'all',
90881               includeDisabledRules: true
90882             });
90883
90884             for (var severity in issuesBySeverity) {
90885               var issues = issuesBySeverity[severity];
90886               var section = severity + '-section';
90887               var issueItem = severity + '-item';
90888               var container = selection.selectAll('.' + section).data(issues.length ? [0] : []);
90889               container.exit().remove();
90890               var containerEnter = container.enter().append('div').attr('class', 'modal-section ' + section + ' fillL2');
90891               containerEnter.append('h3').html(severity === 'warning' ? _t.html('commit.warnings') : _t.html('commit.errors'));
90892               containerEnter.append('ul').attr('class', 'changeset-list');
90893               container = containerEnter.merge(container);
90894               var items = container.select('ul').selectAll('li').data(issues, function (d) {
90895                 return d.id;
90896               });
90897               items.exit().remove();
90898               var itemsEnter = items.enter().append('li').attr('class', issueItem);
90899               var buttons = itemsEnter.append('button').on('mouseover', function (d3_event, d) {
90900                 if (d.entityIds) {
90901                   context.surface().selectAll(utilEntityOrMemberSelector(d.entityIds, context.graph())).classed('hover', true);
90902                 }
90903               }).on('mouseout', function () {
90904                 context.surface().selectAll('.hover').classed('hover', false);
90905               }).on('click', function (d3_event, d) {
90906                 context.validator().focusIssue(d);
90907               });
90908               buttons.call(svgIcon('#iD-icon-alert', 'pre-text'));
90909               buttons.append('strong').attr('class', 'issue-message');
90910               buttons.filter(function (d) {
90911                 return d.tooltip;
90912               }).call(uiTooltip().title(function (d) {
90913                 return d.tooltip;
90914               }).placement('top'));
90915               items = itemsEnter.merge(items);
90916               items.selectAll('.issue-message').html(function (d) {
90917                 return d.message(context);
90918               });
90919             }
90920           }
90921
90922           return commitWarnings;
90923         }
90924
90925         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
90926         // from https://stackoverflow.com/a/25575009
90927
90928         var hashtagRegex = /(#[^\u2000-\u206F\u2E00-\u2E7F\s\\'!"#$%()*,.\/:;<=>?@\[\]^`{|}~]+)/g;
90929         function uiCommit(context) {
90930           var dispatch$1 = dispatch('cancel');
90931
90932           var _userDetails;
90933
90934           var _selection;
90935
90936           var changesetEditor = uiChangesetEditor(context).on('change', changeTags);
90937           var rawTagEditor = uiSectionRawTagEditor('changeset-tag-editor', context).on('change', changeTags).readOnlyTags(readOnlyTags);
90938           var commitChanges = uiSectionChanges(context);
90939           var commitWarnings = uiCommitWarnings(context);
90940
90941           function commit(selection) {
90942             _selection = selection; // Initialize changeset if one does not exist yet.
90943
90944             if (!context.changeset) initChangeset();
90945             loadDerivedChangesetTags();
90946             selection.call(render);
90947           }
90948
90949           function initChangeset() {
90950             // expire stored comment, hashtags, source after cutoff datetime - #3947 #4899
90951             var commentDate = +corePreferences('commentDate') || 0;
90952             var currDate = Date.now();
90953             var cutoff = 2 * 86400 * 1000; // 2 days
90954
90955             if (commentDate > currDate || currDate - commentDate > cutoff) {
90956               corePreferences('comment', null);
90957               corePreferences('hashtags', null);
90958               corePreferences('source', null);
90959             } // load in explicitly-set values, if any
90960
90961
90962             if (context.defaultChangesetComment()) {
90963               corePreferences('comment', context.defaultChangesetComment());
90964               corePreferences('commentDate', Date.now());
90965             }
90966
90967             if (context.defaultChangesetSource()) {
90968               corePreferences('source', context.defaultChangesetSource());
90969               corePreferences('commentDate', Date.now());
90970             }
90971
90972             if (context.defaultChangesetHashtags()) {
90973               corePreferences('hashtags', context.defaultChangesetHashtags());
90974               corePreferences('commentDate', Date.now());
90975             }
90976
90977             var detected = utilDetect();
90978             var tags = {
90979               comment: corePreferences('comment') || '',
90980               created_by: context.cleanTagValue('iD ' + context.version),
90981               host: context.cleanTagValue(detected.host),
90982               locale: context.cleanTagValue(_mainLocalizer.localeCode())
90983             }; // call findHashtags initially - this will remove stored
90984             // hashtags if any hashtags are found in the comment - #4304
90985
90986             findHashtags(tags, true);
90987             var hashtags = corePreferences('hashtags');
90988
90989             if (hashtags) {
90990               tags.hashtags = hashtags;
90991             }
90992
90993             var source = corePreferences('source');
90994
90995             if (source) {
90996               tags.source = source;
90997             }
90998
90999             var photoOverlaysUsed = context.history().photoOverlaysUsed();
91000
91001             if (photoOverlaysUsed.length) {
91002               var sources = (tags.source || '').split(';'); // include this tag for any photo layer
91003
91004               if (sources.indexOf('streetlevel imagery') === -1) {
91005                 sources.push('streetlevel imagery');
91006               } // add the photo overlays used during editing as sources
91007
91008
91009               photoOverlaysUsed.forEach(function (photoOverlay) {
91010                 if (sources.indexOf(photoOverlay) === -1) {
91011                   sources.push(photoOverlay);
91012                 }
91013               });
91014               tags.source = context.cleanTagValue(sources.join(';'));
91015             }
91016
91017             context.changeset = new osmChangeset({
91018               tags: tags
91019             });
91020           } // Calculates read-only metadata tags based on the user's editing session and applies
91021           // them to the changeset.
91022
91023
91024           function loadDerivedChangesetTags() {
91025             var osm = context.connection();
91026             if (!osm) return;
91027             var tags = Object.assign({}, context.changeset.tags); // shallow copy
91028             // assign tags for imagery used
91029
91030             var imageryUsed = context.cleanTagValue(context.history().imageryUsed().join(';'));
91031             tags.imagery_used = imageryUsed || 'None'; // assign tags for closed issues and notes
91032
91033             var osmClosed = osm.getClosedIDs();
91034             var itemType;
91035
91036             if (osmClosed.length) {
91037               tags['closed:note'] = context.cleanTagValue(osmClosed.join(';'));
91038             }
91039
91040             if (services.keepRight) {
91041               var krClosed = services.keepRight.getClosedIDs();
91042
91043               if (krClosed.length) {
91044                 tags['closed:keepright'] = context.cleanTagValue(krClosed.join(';'));
91045               }
91046             }
91047
91048             if (services.improveOSM) {
91049               var iOsmClosed = services.improveOSM.getClosedCounts();
91050
91051               for (itemType in iOsmClosed) {
91052                 tags['closed:improveosm:' + itemType] = context.cleanTagValue(iOsmClosed[itemType].toString());
91053               }
91054             }
91055
91056             if (services.osmose) {
91057               var osmoseClosed = services.osmose.getClosedCounts();
91058
91059               for (itemType in osmoseClosed) {
91060                 tags['closed:osmose:' + itemType] = context.cleanTagValue(osmoseClosed[itemType].toString());
91061               }
91062             } // remove existing issue counts
91063
91064
91065             for (var key in tags) {
91066               if (key.match(/(^warnings:)|(^resolved:)/)) {
91067                 delete tags[key];
91068               }
91069             }
91070
91071             function addIssueCounts(issues, prefix) {
91072               var issuesByType = utilArrayGroupBy(issues, 'type');
91073
91074               for (var issueType in issuesByType) {
91075                 var issuesOfType = issuesByType[issueType];
91076
91077                 if (issuesOfType[0].subtype) {
91078                   var issuesBySubtype = utilArrayGroupBy(issuesOfType, 'subtype');
91079
91080                   for (var issueSubtype in issuesBySubtype) {
91081                     var issuesOfSubtype = issuesBySubtype[issueSubtype];
91082                     tags[prefix + ':' + issueType + ':' + issueSubtype] = context.cleanTagValue(issuesOfSubtype.length.toString());
91083                   }
91084                 } else {
91085                   tags[prefix + ':' + issueType] = context.cleanTagValue(issuesOfType.length.toString());
91086                 }
91087               }
91088             } // add counts of warnings generated by the user's edits
91089
91090
91091             var warnings = context.validator().getIssuesBySeverity({
91092               what: 'edited',
91093               where: 'all',
91094               includeIgnored: true,
91095               includeDisabledRules: true
91096             }).warning;
91097             addIssueCounts(warnings, 'warnings'); // add counts of issues resolved by the user's edits
91098
91099             var resolvedIssues = context.validator().getResolvedIssues();
91100             addIssueCounts(resolvedIssues, 'resolved');
91101             context.changeset = context.changeset.update({
91102               tags: tags
91103             });
91104           }
91105
91106           function render(selection) {
91107             var osm = context.connection();
91108             if (!osm) return;
91109             var header = selection.selectAll('.header').data([0]);
91110             var headerTitle = header.enter().append('div').attr('class', 'header fillL');
91111             headerTitle.append('div').append('h3').html(_t.html('commit.title'));
91112             headerTitle.append('button').attr('class', 'close').on('click', function () {
91113               dispatch$1.call('cancel', this);
91114             }).call(svgIcon('#iD-icon-close'));
91115             var body = selection.selectAll('.body').data([0]);
91116             body = body.enter().append('div').attr('class', 'body').merge(body); // Changeset Section
91117
91118             var changesetSection = body.selectAll('.changeset-editor').data([0]);
91119             changesetSection = changesetSection.enter().append('div').attr('class', 'modal-section changeset-editor').merge(changesetSection);
91120             changesetSection.call(changesetEditor.changesetID(context.changeset.id).tags(context.changeset.tags)); // Warnings
91121
91122             body.call(commitWarnings); // Upload Explanation
91123
91124             var saveSection = body.selectAll('.save-section').data([0]);
91125             saveSection = saveSection.enter().append('div').attr('class', 'modal-section save-section fillL').merge(saveSection);
91126             var prose = saveSection.selectAll('.commit-info').data([0]);
91127
91128             if (prose.enter().size()) {
91129               // first time, make sure to update user details in prose
91130               _userDetails = null;
91131             }
91132
91133             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()
91134             // if needed, because it can trigger a style recalculation
91135
91136             osm.userDetails(function (err, user) {
91137               if (err) return;
91138               if (_userDetails === user) return; // no change
91139
91140               _userDetails = user;
91141               var userLink = select(document.createElement('div'));
91142
91143               if (user.image_url) {
91144                 userLink.append('img').attr('src', user.image_url).attr('class', 'icon pre-text user-icon');
91145               }
91146
91147               userLink.append('a').attr('class', 'user-info').html(user.display_name).attr('href', osm.userURL(user.display_name)).attr('target', '_blank');
91148               prose.html(_t.html('commit.upload_explanation_with_user', {
91149                 user: userLink.html()
91150               }));
91151             }); // Request Review
91152
91153             var requestReview = saveSection.selectAll('.request-review').data([0]); // Enter
91154
91155             var requestReviewEnter = requestReview.enter().append('div').attr('class', 'request-review');
91156             var requestReviewDomId = utilUniqueDomId('commit-input-request-review');
91157             var labelEnter = requestReviewEnter.append('label').attr('for', requestReviewDomId);
91158             labelEnter.append('input').attr('type', 'checkbox').attr('id', requestReviewDomId);
91159             labelEnter.append('span').html(_t.html('commit.request_review')); // Update
91160
91161             requestReview = requestReview.merge(requestReviewEnter);
91162             var requestReviewInput = requestReview.selectAll('input').property('checked', isReviewRequested(context.changeset.tags)).on('change', toggleRequestReview); // Buttons
91163
91164             var buttonSection = saveSection.selectAll('.buttons').data([0]); // enter
91165
91166             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons fillL');
91167             buttonEnter.append('button').attr('class', 'secondary-action button cancel-button').append('span').attr('class', 'label').html(_t.html('commit.cancel'));
91168             var uploadButton = buttonEnter.append('button').attr('class', 'action button save-button');
91169             uploadButton.append('span').attr('class', 'label').html(_t.html('commit.save'));
91170             var uploadBlockerTooltipText = getUploadBlockerMessage(); // update
91171
91172             buttonSection = buttonSection.merge(buttonEnter);
91173             buttonSection.selectAll('.cancel-button').on('click.cancel', function () {
91174               dispatch$1.call('cancel', this);
91175             });
91176             buttonSection.selectAll('.save-button').classed('disabled', uploadBlockerTooltipText !== null).on('click.save', function () {
91177               if (!select(this).classed('disabled')) {
91178                 this.blur(); // avoid keeping focus on the button - #4641
91179
91180                 for (var key in context.changeset.tags) {
91181                   // remove any empty keys before upload
91182                   if (!key) delete context.changeset.tags[key];
91183                 }
91184
91185                 context.uploader().save(context.changeset);
91186               }
91187             }); // remove any existing tooltip
91188
91189             uiTooltip().destroyAny(buttonSection.selectAll('.save-button'));
91190
91191             if (uploadBlockerTooltipText) {
91192               buttonSection.selectAll('.save-button').call(uiTooltip().title(uploadBlockerTooltipText).placement('top'));
91193             } // Raw Tag Editor
91194
91195
91196             var tagSection = body.selectAll('.tag-section.raw-tag-editor').data([0]);
91197             tagSection = tagSection.enter().append('div').attr('class', 'modal-section tag-section raw-tag-editor').merge(tagSection);
91198             tagSection.call(rawTagEditor.tags(Object.assign({}, context.changeset.tags)) // shallow copy
91199             .render);
91200             var changesSection = body.selectAll('.commit-changes-section').data([0]);
91201             changesSection = changesSection.enter().append('div').attr('class', 'modal-section commit-changes-section').merge(changesSection); // Change summary
91202
91203             changesSection.call(commitChanges.render);
91204
91205             function toggleRequestReview() {
91206               var rr = requestReviewInput.property('checked');
91207               updateChangeset({
91208                 review_requested: rr ? 'yes' : undefined
91209               });
91210               tagSection.call(rawTagEditor.tags(Object.assign({}, context.changeset.tags)) // shallow copy
91211               .render);
91212             }
91213           }
91214
91215           function getUploadBlockerMessage() {
91216             var errors = context.validator().getIssuesBySeverity({
91217               what: 'edited',
91218               where: 'all'
91219             }).error;
91220
91221             if (errors.length) {
91222               return _t('commit.outstanding_errors_message', {
91223                 count: errors.length
91224               });
91225             } else {
91226               var hasChangesetComment = context.changeset && context.changeset.tags.comment && context.changeset.tags.comment.trim().length;
91227
91228               if (!hasChangesetComment) {
91229                 return _t('commit.comment_needed_message');
91230               }
91231             }
91232
91233             return null;
91234           }
91235
91236           function changeTags(_, changed, onInput) {
91237             if (changed.hasOwnProperty('comment')) {
91238               if (changed.comment === undefined) {
91239                 changed.comment = '';
91240               }
91241
91242               if (!onInput) {
91243                 corePreferences('comment', changed.comment);
91244                 corePreferences('commentDate', Date.now());
91245               }
91246             }
91247
91248             if (changed.hasOwnProperty('source')) {
91249               if (changed.source === undefined) {
91250                 corePreferences('source', null);
91251               } else if (!onInput) {
91252                 corePreferences('source', changed.source);
91253                 corePreferences('commentDate', Date.now());
91254               }
91255             } // no need to update `prefs` for `hashtags` here since it's done in `updateChangeset`
91256
91257
91258             updateChangeset(changed, onInput);
91259
91260             if (_selection) {
91261               _selection.call(render);
91262             }
91263           }
91264
91265           function findHashtags(tags, commentOnly) {
91266             var detectedHashtags = commentHashtags();
91267
91268             if (detectedHashtags.length) {
91269               // always remove stored hashtags if there are hashtags in the comment - #4304
91270               corePreferences('hashtags', null);
91271             }
91272
91273             if (!detectedHashtags.length || !commentOnly) {
91274               detectedHashtags = detectedHashtags.concat(hashtagHashtags());
91275             }
91276
91277             var allLowerCase = new Set();
91278             return detectedHashtags.filter(function (hashtag) {
91279               // Compare tags as lowercase strings, but keep original case tags
91280               var lowerCase = hashtag.toLowerCase();
91281
91282               if (!allLowerCase.has(lowerCase)) {
91283                 allLowerCase.add(lowerCase);
91284                 return true;
91285               }
91286
91287               return false;
91288             }); // Extract hashtags from `comment`
91289
91290             function commentHashtags() {
91291               var matches = (tags.comment || '').replace(/http\S*/g, '') // drop anything that looks like a URL - #4289
91292               .match(hashtagRegex);
91293               return matches || [];
91294             } // Extract and clean hashtags from `hashtags`
91295
91296
91297             function hashtagHashtags() {
91298               var matches = (tags.hashtags || '').split(/[,;\s]+/).map(function (s) {
91299                 if (s[0] !== '#') {
91300                   s = '#' + s;
91301                 } // prepend '#'
91302
91303
91304                 var matched = s.match(hashtagRegex);
91305                 return matched && matched[0];
91306               }).filter(Boolean); // exclude falsy
91307
91308               return matches || [];
91309             }
91310           }
91311
91312           function isReviewRequested(tags) {
91313             var rr = tags.review_requested;
91314             if (rr === undefined) return false;
91315             rr = rr.trim().toLowerCase();
91316             return !(rr === '' || rr === 'no');
91317           }
91318
91319           function updateChangeset(changed, onInput) {
91320             var tags = Object.assign({}, context.changeset.tags); // shallow copy
91321
91322             Object.keys(changed).forEach(function (k) {
91323               var v = changed[k];
91324               k = context.cleanTagKey(k);
91325               if (readOnlyTags.indexOf(k) !== -1) return;
91326
91327               if (v === undefined) {
91328                 delete tags[k];
91329               } else if (onInput) {
91330                 tags[k] = v;
91331               } else {
91332                 tags[k] = context.cleanTagValue(v);
91333               }
91334             });
91335
91336             if (!onInput) {
91337               // when changing the comment, override hashtags with any found in comment.
91338               var commentOnly = changed.hasOwnProperty('comment') && changed.comment !== '';
91339               var arr = findHashtags(tags, commentOnly);
91340
91341               if (arr.length) {
91342                 tags.hashtags = context.cleanTagValue(arr.join(';'));
91343                 corePreferences('hashtags', tags.hashtags);
91344               } else {
91345                 delete tags.hashtags;
91346                 corePreferences('hashtags', null);
91347               }
91348             } // always update userdetails, just in case user reauthenticates as someone else
91349
91350
91351             if (_userDetails && _userDetails.changesets_count !== undefined) {
91352               var changesetsCount = parseInt(_userDetails.changesets_count, 10) + 1; // #4283
91353
91354               tags.changesets_count = String(changesetsCount); // first 100 edits - new user
91355
91356               if (changesetsCount <= 100) {
91357                 var s;
91358                 s = corePreferences('walkthrough_completed');
91359
91360                 if (s) {
91361                   tags['ideditor:walkthrough_completed'] = s;
91362                 }
91363
91364                 s = corePreferences('walkthrough_progress');
91365
91366                 if (s) {
91367                   tags['ideditor:walkthrough_progress'] = s;
91368                 }
91369
91370                 s = corePreferences('walkthrough_started');
91371
91372                 if (s) {
91373                   tags['ideditor:walkthrough_started'] = s;
91374                 }
91375               }
91376             } else {
91377               delete tags.changesets_count;
91378             }
91379
91380             if (!fastDeepEqual(context.changeset.tags, tags)) {
91381               context.changeset = context.changeset.update({
91382                 tags: tags
91383               });
91384             }
91385           }
91386
91387           commit.reset = function () {
91388             context.changeset = null;
91389           };
91390
91391           return utilRebind(commit, dispatch$1, 'on');
91392         }
91393
91394         var globalIsFinite = global_1.isFinite;
91395
91396         // `Number.isFinite` method
91397         // https://tc39.github.io/ecma262/#sec-number.isfinite
91398         var numberIsFinite = Number.isFinite || function isFinite(it) {
91399           return typeof it == 'number' && globalIsFinite(it);
91400         };
91401
91402         // `Number.isFinite` method
91403         // https://tc39.github.io/ecma262/#sec-number.isfinite
91404         _export({ target: 'Number', stat: true }, { isFinite: numberIsFinite });
91405
91406         var RADIUS = 6378137;
91407         var FLATTENING = 1 / 298.257223563;
91408         var POLAR_RADIUS$1 = 6356752.3142;
91409         var wgs84 = {
91410           RADIUS: RADIUS,
91411           FLATTENING: FLATTENING,
91412           POLAR_RADIUS: POLAR_RADIUS$1
91413         };
91414
91415         var geometry_1 = geometry;
91416         var ring = ringArea;
91417
91418         function geometry(_) {
91419           var area = 0,
91420               i;
91421
91422           switch (_.type) {
91423             case 'Polygon':
91424               return polygonArea(_.coordinates);
91425
91426             case 'MultiPolygon':
91427               for (i = 0; i < _.coordinates.length; i++) {
91428                 area += polygonArea(_.coordinates[i]);
91429               }
91430
91431               return area;
91432
91433             case 'Point':
91434             case 'MultiPoint':
91435             case 'LineString':
91436             case 'MultiLineString':
91437               return 0;
91438
91439             case 'GeometryCollection':
91440               for (i = 0; i < _.geometries.length; i++) {
91441                 area += geometry(_.geometries[i]);
91442               }
91443
91444               return area;
91445           }
91446         }
91447
91448         function polygonArea(coords) {
91449           var area = 0;
91450
91451           if (coords && coords.length > 0) {
91452             area += Math.abs(ringArea(coords[0]));
91453
91454             for (var i = 1; i < coords.length; i++) {
91455               area -= Math.abs(ringArea(coords[i]));
91456             }
91457           }
91458
91459           return area;
91460         }
91461         /**
91462          * Calculate the approximate area of the polygon were it projected onto
91463          *     the earth.  Note that this area will be positive if ring is oriented
91464          *     clockwise, otherwise it will be negative.
91465          *
91466          * Reference:
91467          * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
91468          *     Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
91469          *     Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
91470          *
91471          * Returns:
91472          * {float} The approximate signed geodesic area of the polygon in square
91473          *     meters.
91474          */
91475
91476
91477         function ringArea(coords) {
91478           var p1,
91479               p2,
91480               p3,
91481               lowerIndex,
91482               middleIndex,
91483               upperIndex,
91484               i,
91485               area = 0,
91486               coordsLength = coords.length;
91487
91488           if (coordsLength > 2) {
91489             for (i = 0; i < coordsLength; i++) {
91490               if (i === coordsLength - 2) {
91491                 // i = N-2
91492                 lowerIndex = coordsLength - 2;
91493                 middleIndex = coordsLength - 1;
91494                 upperIndex = 0;
91495               } else if (i === coordsLength - 1) {
91496                 // i = N-1
91497                 lowerIndex = coordsLength - 1;
91498                 middleIndex = 0;
91499                 upperIndex = 1;
91500               } else {
91501                 // i = 0 to N-3
91502                 lowerIndex = i;
91503                 middleIndex = i + 1;
91504                 upperIndex = i + 2;
91505               }
91506
91507               p1 = coords[lowerIndex];
91508               p2 = coords[middleIndex];
91509               p3 = coords[upperIndex];
91510               area += (rad(p3[0]) - rad(p1[0])) * Math.sin(rad(p2[1]));
91511             }
91512
91513             area = area * wgs84.RADIUS * wgs84.RADIUS / 2;
91514           }
91515
91516           return area;
91517         }
91518
91519         function rad(_) {
91520           return _ * Math.PI / 180;
91521         }
91522
91523         var geojsonArea = {
91524           geometry: geometry_1,
91525           ring: ring
91526         };
91527
91528         function toRadians(angleInDegrees) {
91529           return angleInDegrees * Math.PI / 180;
91530         }
91531
91532         function toDegrees(angleInRadians) {
91533           return angleInRadians * 180 / Math.PI;
91534         }
91535
91536         function offset(c1, distance, bearing) {
91537           var lat1 = toRadians(c1[1]);
91538           var lon1 = toRadians(c1[0]);
91539           var dByR = distance / 6378137; // distance divided by 6378137 (radius of the earth) wgs84
91540
91541           var lat = Math.asin(Math.sin(lat1) * Math.cos(dByR) + Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing));
91542           var lon = lon1 + Math.atan2(Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1), Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat));
91543           return [toDegrees(lon), toDegrees(lat)];
91544         }
91545
91546         function validateCenter(center) {
91547           var validCenterLengths = [2, 3];
91548
91549           if (!Array.isArray(center) || !validCenterLengths.includes(center.length)) {
91550             throw new Error("ERROR! Center has to be an array of length two or three");
91551           }
91552
91553           var _center = _slicedToArray(center, 2),
91554               lng = _center[0],
91555               lat = _center[1];
91556
91557           if (typeof lng !== "number" || typeof lat !== "number") {
91558             throw new Error("ERROR! Longitude and Latitude has to be numbers but where ".concat(_typeof(lng), " and ").concat(_typeof(lat)));
91559           }
91560
91561           if (lng > 180 || lng < -180) {
91562             throw new Error("ERROR! Longitude has to be between -180 and 180 but was ".concat(lng));
91563           }
91564
91565           if (lat > 90 || lat < -90) {
91566             throw new Error("ERROR! Latitude has to be between -90 and 90 but was ".concat(lat));
91567           }
91568         }
91569
91570         function validateRadius(radius) {
91571           if (typeof radius !== "number") {
91572             throw new Error("ERROR! Radius has to be a positive number but was: ".concat(_typeof(radius)));
91573           }
91574
91575           if (radius <= 0) {
91576             throw new Error("ERROR! Radius has to be a positive number but was: ".concat(radius));
91577           }
91578         }
91579
91580         function validateNumberOfSegments(numberOfSegments) {
91581           if (typeof numberOfSegments !== "number" && numberOfSegments !== undefined) {
91582             throw new Error("ERROR! Number of segments has to be a number but was: ".concat(_typeof(numberOfSegments)));
91583           }
91584
91585           if (numberOfSegments < 3) {
91586             throw new Error("ERROR! Number of segments has to be at least 3 but was: ".concat(numberOfSegments));
91587           }
91588         }
91589
91590         function validateInput(_ref) {
91591           var center = _ref.center,
91592               radius = _ref.radius,
91593               numberOfSegments = _ref.numberOfSegments;
91594           validateCenter(center);
91595           validateRadius(radius);
91596           validateNumberOfSegments(numberOfSegments);
91597         }
91598
91599         var circleToPolygon = function circleToPolygon(center, radius, numberOfSegments) {
91600           var n = numberOfSegments ? numberOfSegments : 32; // validateInput() throws error on invalid input and do nothing on valid input
91601
91602           validateInput({
91603             center: center,
91604             radius: radius,
91605             numberOfSegments: numberOfSegments
91606           });
91607           var coordinates = [];
91608
91609           for (var i = 0; i < n; ++i) {
91610             coordinates.push(offset(center, radius, 2 * Math.PI * -i / n));
91611           }
91612
91613           coordinates.push(coordinates[0]);
91614           return {
91615             type: "Polygon",
91616             coordinates: [coordinates]
91617           };
91618         };
91619
91620         // `Number.EPSILON` constant
91621         // https://tc39.github.io/ecma262/#sec-number.epsilon
91622         _export({ target: 'Number', stat: true }, {
91623           EPSILON: Math.pow(2, -52)
91624         });
91625
91626         /**
91627          * splaytree v3.0.1
91628          * Fast Splay tree for Node and browser
91629          *
91630          * @author Alexander Milevski <info@w8r.name>
91631          * @license MIT
91632          * @preserve
91633          */
91634         var Node$1 = function Node(key, data) {
91635           _classCallCheck(this, Node);
91636
91637           this.next = null;
91638           this.key = key;
91639           this.data = data;
91640           this.left = null;
91641           this.right = null;
91642         };
91643         /* follows "An implementation of top-down splaying"
91644          * by D. Sleator <sleator@cs.cmu.edu> March 1992
91645          */
91646
91647
91648         function DEFAULT_COMPARE$1(a, b) {
91649           return a > b ? 1 : a < b ? -1 : 0;
91650         }
91651         /**
91652          * Simple top down splay, not requiring i to be in the tree t.
91653          */
91654
91655
91656         function splay(i, t, comparator) {
91657           var N = new Node$1(null, null);
91658           var l = N;
91659           var r = N;
91660
91661           while (true) {
91662             var cmp = comparator(i, t.key); //if (i < t.key) {
91663
91664             if (cmp < 0) {
91665               if (t.left === null) break; //if (i < t.left.key) {
91666
91667               if (comparator(i, t.left.key) < 0) {
91668                 var y = t.left;
91669                 /* rotate right */
91670
91671                 t.left = y.right;
91672                 y.right = t;
91673                 t = y;
91674                 if (t.left === null) break;
91675               }
91676
91677               r.left = t;
91678               /* link right */
91679
91680               r = t;
91681               t = t.left; //} else if (i > t.key) {
91682             } else if (cmp > 0) {
91683               if (t.right === null) break; //if (i > t.right.key) {
91684
91685               if (comparator(i, t.right.key) > 0) {
91686                 var _y = t.right;
91687                 /* rotate left */
91688
91689                 t.right = _y.left;
91690                 _y.left = t;
91691                 t = _y;
91692                 if (t.right === null) break;
91693               }
91694
91695               l.right = t;
91696               /* link left */
91697
91698               l = t;
91699               t = t.right;
91700             } else break;
91701           }
91702           /* assemble */
91703
91704
91705           l.right = t.left;
91706           r.left = t.right;
91707           t.left = N.right;
91708           t.right = N.left;
91709           return t;
91710         }
91711
91712         function _insert(i, data, t, comparator) {
91713           var node = new Node$1(i, data);
91714
91715           if (t === null) {
91716             node.left = node.right = null;
91717             return node;
91718           }
91719
91720           t = splay(i, t, comparator);
91721           var cmp = comparator(i, t.key);
91722
91723           if (cmp < 0) {
91724             node.left = t.left;
91725             node.right = t;
91726             t.left = null;
91727           } else if (cmp >= 0) {
91728             node.right = t.right;
91729             node.left = t;
91730             t.right = null;
91731           }
91732
91733           return node;
91734         }
91735
91736         function _split(key, v, comparator) {
91737           var left = null;
91738           var right = null;
91739
91740           if (v) {
91741             v = splay(key, v, comparator);
91742             var cmp = comparator(v.key, key);
91743
91744             if (cmp === 0) {
91745               left = v.left;
91746               right = v.right;
91747             } else if (cmp < 0) {
91748               right = v.right;
91749               v.right = null;
91750               left = v;
91751             } else {
91752               left = v.left;
91753               v.left = null;
91754               right = v;
91755             }
91756           }
91757
91758           return {
91759             left: left,
91760             right: right
91761           };
91762         }
91763
91764         function merge$4(left, right, comparator) {
91765           if (right === null) return left;
91766           if (left === null) return right;
91767           right = splay(left.key, right, comparator);
91768           right.left = left;
91769           return right;
91770         }
91771         /**
91772          * Prints level of the tree
91773          */
91774
91775
91776         function printRow(root, prefix, isTail, out, printNode) {
91777           if (root) {
91778             out("".concat(prefix).concat(isTail ? '└── ' : '├── ').concat(printNode(root), "\n"));
91779             var indent = prefix + (isTail ? '    ' : '│   ');
91780             if (root.left) printRow(root.left, indent, false, out, printNode);
91781             if (root.right) printRow(root.right, indent, true, out, printNode);
91782           }
91783         }
91784
91785         var Tree = /*#__PURE__*/function () {
91786           function Tree() {
91787             var comparator = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_COMPARE$1;
91788
91789             _classCallCheck(this, Tree);
91790
91791             this._root = null;
91792             this._size = 0;
91793             this._comparator = comparator;
91794           }
91795           /**
91796            * Inserts a key, allows duplicates
91797            */
91798
91799
91800           _createClass(Tree, [{
91801             key: "insert",
91802             value: function insert(key, data) {
91803               this._size++;
91804               return this._root = _insert(key, data, this._root, this._comparator);
91805             }
91806             /**
91807              * Adds a key, if it is not present in the tree
91808              */
91809
91810           }, {
91811             key: "add",
91812             value: function add(key, data) {
91813               var node = new Node$1(key, data);
91814
91815               if (this._root === null) {
91816                 node.left = node.right = null;
91817                 this._size++;
91818                 this._root = node;
91819               }
91820
91821               var comparator = this._comparator;
91822               var t = splay(key, this._root, comparator);
91823               var cmp = comparator(key, t.key);
91824               if (cmp === 0) this._root = t;else {
91825                 if (cmp < 0) {
91826                   node.left = t.left;
91827                   node.right = t;
91828                   t.left = null;
91829                 } else if (cmp > 0) {
91830                   node.right = t.right;
91831                   node.left = t;
91832                   t.right = null;
91833                 }
91834
91835                 this._size++;
91836                 this._root = node;
91837               }
91838               return this._root;
91839             }
91840             /**
91841              * @param  {Key} key
91842              * @return {Node|null}
91843              */
91844
91845           }, {
91846             key: "remove",
91847             value: function remove(key) {
91848               this._root = this._remove(key, this._root, this._comparator);
91849             }
91850             /**
91851              * Deletes i from the tree if it's there
91852              */
91853
91854           }, {
91855             key: "_remove",
91856             value: function _remove(i, t, comparator) {
91857               var x;
91858               if (t === null) return null;
91859               t = splay(i, t, comparator);
91860               var cmp = comparator(i, t.key);
91861
91862               if (cmp === 0) {
91863                 /* found it */
91864                 if (t.left === null) {
91865                   x = t.right;
91866                 } else {
91867                   x = splay(i, t.left, comparator);
91868                   x.right = t.right;
91869                 }
91870
91871                 this._size--;
91872                 return x;
91873               }
91874
91875               return t;
91876               /* It wasn't there */
91877             }
91878             /**
91879              * Removes and returns the node with smallest key
91880              */
91881
91882           }, {
91883             key: "pop",
91884             value: function pop() {
91885               var node = this._root;
91886
91887               if (node) {
91888                 while (node.left) {
91889                   node = node.left;
91890                 }
91891
91892                 this._root = splay(node.key, this._root, this._comparator);
91893                 this._root = this._remove(node.key, this._root, this._comparator);
91894                 return {
91895                   key: node.key,
91896                   data: node.data
91897                 };
91898               }
91899
91900               return null;
91901             }
91902             /**
91903              * Find without splaying
91904              */
91905
91906           }, {
91907             key: "findStatic",
91908             value: function findStatic(key) {
91909               var current = this._root;
91910               var compare = this._comparator;
91911
91912               while (current) {
91913                 var cmp = compare(key, current.key);
91914                 if (cmp === 0) return current;else if (cmp < 0) current = current.left;else current = current.right;
91915               }
91916
91917               return null;
91918             }
91919           }, {
91920             key: "find",
91921             value: function find(key) {
91922               if (this._root) {
91923                 this._root = splay(key, this._root, this._comparator);
91924                 if (this._comparator(key, this._root.key) !== 0) return null;
91925               }
91926
91927               return this._root;
91928             }
91929           }, {
91930             key: "contains",
91931             value: function contains(key) {
91932               var current = this._root;
91933               var compare = this._comparator;
91934
91935               while (current) {
91936                 var cmp = compare(key, current.key);
91937                 if (cmp === 0) return true;else if (cmp < 0) current = current.left;else current = current.right;
91938               }
91939
91940               return false;
91941             }
91942           }, {
91943             key: "forEach",
91944             value: function forEach(visitor, ctx) {
91945               var current = this._root;
91946               var Q = [];
91947               /* Initialize stack s */
91948
91949               var done = false;
91950
91951               while (!done) {
91952                 if (current !== null) {
91953                   Q.push(current);
91954                   current = current.left;
91955                 } else {
91956                   if (Q.length !== 0) {
91957                     current = Q.pop();
91958                     visitor.call(ctx, current);
91959                     current = current.right;
91960                   } else done = true;
91961                 }
91962               }
91963
91964               return this;
91965             }
91966             /**
91967              * Walk key range from `low` to `high`. Stops if `fn` returns a value.
91968              */
91969
91970           }, {
91971             key: "range",
91972             value: function range(low, high, fn, ctx) {
91973               var Q = [];
91974               var compare = this._comparator;
91975               var node = this._root;
91976               var cmp;
91977
91978               while (Q.length !== 0 || node) {
91979                 if (node) {
91980                   Q.push(node);
91981                   node = node.left;
91982                 } else {
91983                   node = Q.pop();
91984                   cmp = compare(node.key, high);
91985
91986                   if (cmp > 0) {
91987                     break;
91988                   } else if (compare(node.key, low) >= 0) {
91989                     if (fn.call(ctx, node)) return this; // stop if smth is returned
91990                   }
91991
91992                   node = node.right;
91993                 }
91994               }
91995
91996               return this;
91997             }
91998             /**
91999              * Returns array of keys
92000              */
92001
92002           }, {
92003             key: "keys",
92004             value: function keys() {
92005               var keys = [];
92006               this.forEach(function (_ref) {
92007                 var key = _ref.key;
92008                 return keys.push(key);
92009               });
92010               return keys;
92011             }
92012             /**
92013              * Returns array of all the data in the nodes
92014              */
92015
92016           }, {
92017             key: "values",
92018             value: function values() {
92019               var values = [];
92020               this.forEach(function (_ref2) {
92021                 var data = _ref2.data;
92022                 return values.push(data);
92023               });
92024               return values;
92025             }
92026           }, {
92027             key: "min",
92028             value: function min() {
92029               if (this._root) return this.minNode(this._root).key;
92030               return null;
92031             }
92032           }, {
92033             key: "max",
92034             value: function max() {
92035               if (this._root) return this.maxNode(this._root).key;
92036               return null;
92037             }
92038           }, {
92039             key: "minNode",
92040             value: function minNode() {
92041               var t = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._root;
92042               if (t) while (t.left) {
92043                 t = t.left;
92044               }
92045               return t;
92046             }
92047           }, {
92048             key: "maxNode",
92049             value: function maxNode() {
92050               var t = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._root;
92051               if (t) while (t.right) {
92052                 t = t.right;
92053               }
92054               return t;
92055             }
92056             /**
92057              * Returns node at given index
92058              */
92059
92060           }, {
92061             key: "at",
92062             value: function at(index) {
92063               var current = this._root;
92064               var done = false;
92065               var i = 0;
92066               var Q = [];
92067
92068               while (!done) {
92069                 if (current) {
92070                   Q.push(current);
92071                   current = current.left;
92072                 } else {
92073                   if (Q.length > 0) {
92074                     current = Q.pop();
92075                     if (i === index) return current;
92076                     i++;
92077                     current = current.right;
92078                   } else done = true;
92079                 }
92080               }
92081
92082               return null;
92083             }
92084           }, {
92085             key: "next",
92086             value: function next(d) {
92087               var root = this._root;
92088               var successor = null;
92089
92090               if (d.right) {
92091                 successor = d.right;
92092
92093                 while (successor.left) {
92094                   successor = successor.left;
92095                 }
92096
92097                 return successor;
92098               }
92099
92100               var comparator = this._comparator;
92101
92102               while (root) {
92103                 var cmp = comparator(d.key, root.key);
92104                 if (cmp === 0) break;else if (cmp < 0) {
92105                   successor = root;
92106                   root = root.left;
92107                 } else root = root.right;
92108               }
92109
92110               return successor;
92111             }
92112           }, {
92113             key: "prev",
92114             value: function prev(d) {
92115               var root = this._root;
92116               var predecessor = null;
92117
92118               if (d.left !== null) {
92119                 predecessor = d.left;
92120
92121                 while (predecessor.right) {
92122                   predecessor = predecessor.right;
92123                 }
92124
92125                 return predecessor;
92126               }
92127
92128               var comparator = this._comparator;
92129
92130               while (root) {
92131                 var cmp = comparator(d.key, root.key);
92132                 if (cmp === 0) break;else if (cmp < 0) root = root.left;else {
92133                   predecessor = root;
92134                   root = root.right;
92135                 }
92136               }
92137
92138               return predecessor;
92139             }
92140           }, {
92141             key: "clear",
92142             value: function clear() {
92143               this._root = null;
92144               this._size = 0;
92145               return this;
92146             }
92147           }, {
92148             key: "toList",
92149             value: function toList() {
92150               return _toList(this._root);
92151             }
92152             /**
92153              * Bulk-load items. Both array have to be same size
92154              */
92155
92156           }, {
92157             key: "load",
92158             value: function load(keys) {
92159               var values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
92160               var presort = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
92161               var size = keys.length;
92162               var comparator = this._comparator; // sort if needed
92163
92164               if (presort) sort$1(keys, values, 0, size - 1, comparator);
92165
92166               if (this._root === null) {
92167                 // empty tree
92168                 this._root = loadRecursive$1(keys, values, 0, size);
92169                 this._size = size;
92170               } else {
92171                 // that re-builds the whole tree from two in-order traversals
92172                 var mergedList = mergeLists(this.toList(), createList(keys, values), comparator);
92173                 size = this._size + size;
92174                 this._root = sortedListToBST({
92175                   head: mergedList
92176                 }, 0, size);
92177               }
92178
92179               return this;
92180             }
92181           }, {
92182             key: "isEmpty",
92183             value: function isEmpty() {
92184               return this._root === null;
92185             }
92186           }, {
92187             key: "toString",
92188             value: function toString() {
92189               var printNode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function (n) {
92190                 return String(n.key);
92191               };
92192               var out = [];
92193               printRow(this._root, '', true, function (v) {
92194                 return out.push(v);
92195               }, printNode);
92196               return out.join('');
92197             }
92198           }, {
92199             key: "update",
92200             value: function update(key, newKey, newData) {
92201               var comparator = this._comparator;
92202
92203               var _split2 = _split(key, this._root, comparator),
92204                   left = _split2.left,
92205                   right = _split2.right;
92206
92207               if (comparator(key, newKey) < 0) {
92208                 right = _insert(newKey, newData, right, comparator);
92209               } else {
92210                 left = _insert(newKey, newData, left, comparator);
92211               }
92212
92213               this._root = merge$4(left, right, comparator);
92214             }
92215           }, {
92216             key: "split",
92217             value: function split(key) {
92218               return _split(key, this._root, this._comparator);
92219             }
92220           }, {
92221             key: "size",
92222             get: function get() {
92223               return this._size;
92224             }
92225           }, {
92226             key: "root",
92227             get: function get() {
92228               return this._root;
92229             }
92230           }]);
92231
92232           return Tree;
92233         }();
92234
92235         function loadRecursive$1(keys, values, start, end) {
92236           var size = end - start;
92237
92238           if (size > 0) {
92239             var middle = start + Math.floor(size / 2);
92240             var key = keys[middle];
92241             var data = values[middle];
92242             var node = new Node$1(key, data);
92243             node.left = loadRecursive$1(keys, values, start, middle);
92244             node.right = loadRecursive$1(keys, values, middle + 1, end);
92245             return node;
92246           }
92247
92248           return null;
92249         }
92250
92251         function createList(keys, values) {
92252           var head = new Node$1(null, null);
92253           var p = head;
92254
92255           for (var i = 0; i < keys.length; i++) {
92256             p = p.next = new Node$1(keys[i], values[i]);
92257           }
92258
92259           p.next = null;
92260           return head.next;
92261         }
92262
92263         function _toList(root) {
92264           var current = root;
92265           var Q = [];
92266           var done = false;
92267           var head = new Node$1(null, null);
92268           var p = head;
92269
92270           while (!done) {
92271             if (current) {
92272               Q.push(current);
92273               current = current.left;
92274             } else {
92275               if (Q.length > 0) {
92276                 current = p = p.next = Q.pop();
92277                 current = current.right;
92278               } else done = true;
92279             }
92280           }
92281
92282           p.next = null; // that'll work even if the tree was empty
92283
92284           return head.next;
92285         }
92286
92287         function sortedListToBST(list, start, end) {
92288           var size = end - start;
92289
92290           if (size > 0) {
92291             var middle = start + Math.floor(size / 2);
92292             var left = sortedListToBST(list, start, middle);
92293             var root = list.head;
92294             root.left = left;
92295             list.head = list.head.next;
92296             root.right = sortedListToBST(list, middle + 1, end);
92297             return root;
92298           }
92299
92300           return null;
92301         }
92302
92303         function mergeLists(l1, l2, compare) {
92304           var head = new Node$1(null, null); // dummy
92305
92306           var p = head;
92307           var p1 = l1;
92308           var p2 = l2;
92309
92310           while (p1 !== null && p2 !== null) {
92311             if (compare(p1.key, p2.key) < 0) {
92312               p.next = p1;
92313               p1 = p1.next;
92314             } else {
92315               p.next = p2;
92316               p2 = p2.next;
92317             }
92318
92319             p = p.next;
92320           }
92321
92322           if (p1 !== null) {
92323             p.next = p1;
92324           } else if (p2 !== null) {
92325             p.next = p2;
92326           }
92327
92328           return head.next;
92329         }
92330
92331         function sort$1(keys, values, left, right, compare) {
92332           if (left >= right) return;
92333           var pivot = keys[left + right >> 1];
92334           var i = left - 1;
92335           var j = right + 1;
92336
92337           while (true) {
92338             do {
92339               i++;
92340             } while (compare(keys[i], pivot) < 0);
92341
92342             do {
92343               j--;
92344             } while (compare(keys[j], pivot) > 0);
92345
92346             if (i >= j) break;
92347             var tmp = keys[i];
92348             keys[i] = keys[j];
92349             keys[j] = tmp;
92350             tmp = values[i];
92351             values[i] = values[j];
92352             values[j] = tmp;
92353           }
92354
92355           sort$1(keys, values, left, j, compare);
92356           sort$1(keys, values, j + 1, right, compare);
92357         }
92358
92359         function _classCallCheck$1(instance, Constructor) {
92360           if (!(instance instanceof Constructor)) {
92361             throw new TypeError("Cannot call a class as a function");
92362           }
92363         }
92364
92365         function _defineProperties$1(target, props) {
92366           for (var i = 0; i < props.length; i++) {
92367             var descriptor = props[i];
92368             descriptor.enumerable = descriptor.enumerable || false;
92369             descriptor.configurable = true;
92370             if ("value" in descriptor) descriptor.writable = true;
92371             Object.defineProperty(target, descriptor.key, descriptor);
92372           }
92373         }
92374
92375         function _createClass$1(Constructor, protoProps, staticProps) {
92376           if (protoProps) _defineProperties$1(Constructor.prototype, protoProps);
92377           if (staticProps) _defineProperties$1(Constructor, staticProps);
92378           return Constructor;
92379         }
92380         /**
92381          * A bounding box has the format:
92382          *
92383          *  { ll: { x: xmin, y: ymin }, ur: { x: xmax, y: ymax } }
92384          *
92385          */
92386
92387
92388         var isInBbox = function isInBbox(bbox, point) {
92389           return bbox.ll.x <= point.x && point.x <= bbox.ur.x && bbox.ll.y <= point.y && point.y <= bbox.ur.y;
92390         };
92391         /* Returns either null, or a bbox (aka an ordered pair of points)
92392          * If there is only one point of overlap, a bbox with identical points
92393          * will be returned */
92394
92395
92396         var getBboxOverlap = function getBboxOverlap(b1, b2) {
92397           // check if the bboxes overlap at all
92398           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
92399
92400           var lowerX = b1.ll.x < b2.ll.x ? b2.ll.x : b1.ll.x;
92401           var upperX = b1.ur.x < b2.ur.x ? b1.ur.x : b2.ur.x; // find the middle two Y values
92402
92403           var lowerY = b1.ll.y < b2.ll.y ? b2.ll.y : b1.ll.y;
92404           var upperY = b1.ur.y < b2.ur.y ? b1.ur.y : b2.ur.y; // put those middle values together to get the overlap
92405
92406           return {
92407             ll: {
92408               x: lowerX,
92409               y: lowerY
92410             },
92411             ur: {
92412               x: upperX,
92413               y: upperY
92414             }
92415           };
92416         };
92417         /* Javascript doesn't do integer math. Everything is
92418          * floating point with percision Number.EPSILON.
92419          *
92420          * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON
92421          */
92422
92423
92424         var epsilon$2 = Number.EPSILON; // IE Polyfill
92425
92426         if (epsilon$2 === undefined) epsilon$2 = Math.pow(2, -52);
92427         var EPSILON_SQ = epsilon$2 * epsilon$2;
92428         /* FLP comparator */
92429
92430         var cmp = function cmp(a, b) {
92431           // check if they're both 0
92432           if (-epsilon$2 < a && a < epsilon$2) {
92433             if (-epsilon$2 < b && b < epsilon$2) {
92434               return 0;
92435             }
92436           } // check if they're flp equal
92437
92438
92439           var ab = a - b;
92440
92441           if (ab * ab < EPSILON_SQ * a * b) {
92442             return 0;
92443           } // normal comparison
92444
92445
92446           return a < b ? -1 : 1;
92447         };
92448         /**
92449          * This class rounds incoming values sufficiently so that
92450          * floating points problems are, for the most part, avoided.
92451          *
92452          * Incoming points are have their x & y values tested against
92453          * all previously seen x & y values. If either is 'too close'
92454          * to a previously seen value, it's value is 'snapped' to the
92455          * previously seen value.
92456          *
92457          * All points should be rounded by this class before being
92458          * stored in any data structures in the rest of this algorithm.
92459          */
92460
92461
92462         var PtRounder = /*#__PURE__*/function () {
92463           function PtRounder() {
92464             _classCallCheck$1(this, PtRounder);
92465
92466             this.reset();
92467           }
92468
92469           _createClass$1(PtRounder, [{
92470             key: "reset",
92471             value: function reset() {
92472               this.xRounder = new CoordRounder();
92473               this.yRounder = new CoordRounder();
92474             }
92475           }, {
92476             key: "round",
92477             value: function round(x, y) {
92478               return {
92479                 x: this.xRounder.round(x),
92480                 y: this.yRounder.round(y)
92481               };
92482             }
92483           }]);
92484
92485           return PtRounder;
92486         }();
92487
92488         var CoordRounder = /*#__PURE__*/function () {
92489           function CoordRounder() {
92490             _classCallCheck$1(this, CoordRounder);
92491
92492             this.tree = new Tree(); // preseed with 0 so we don't end up with values < Number.EPSILON
92493
92494             this.round(0);
92495           } // Note: this can rounds input values backwards or forwards.
92496           //       You might ask, why not restrict this to just rounding
92497           //       forwards? Wouldn't that allow left endpoints to always
92498           //       remain left endpoints during splitting (never change to
92499           //       right). No - it wouldn't, because we snap intersections
92500           //       to endpoints (to establish independence from the segment
92501           //       angle for t-intersections).
92502
92503
92504           _createClass$1(CoordRounder, [{
92505             key: "round",
92506             value: function round(coord) {
92507               var node = this.tree.add(coord);
92508               var prevNode = this.tree.prev(node);
92509
92510               if (prevNode !== null && cmp(node.key, prevNode.key) === 0) {
92511                 this.tree.remove(coord);
92512                 return prevNode.key;
92513               }
92514
92515               var nextNode = this.tree.next(node);
92516
92517               if (nextNode !== null && cmp(node.key, nextNode.key) === 0) {
92518                 this.tree.remove(coord);
92519                 return nextNode.key;
92520               }
92521
92522               return coord;
92523             }
92524           }]);
92525
92526           return CoordRounder;
92527         }(); // singleton available by import
92528
92529
92530         var rounder = new PtRounder();
92531         /* Cross Product of two vectors with first point at origin */
92532
92533         var crossProduct$1 = function crossProduct(a, b) {
92534           return a.x * b.y - a.y * b.x;
92535         };
92536         /* Dot Product of two vectors with first point at origin */
92537
92538
92539         var dotProduct$1 = function dotProduct(a, b) {
92540           return a.x * b.x + a.y * b.y;
92541         };
92542         /* Comparator for two vectors with same starting point */
92543
92544
92545         var compareVectorAngles = function compareVectorAngles(basePt, endPt1, endPt2) {
92546           var v1 = {
92547             x: endPt1.x - basePt.x,
92548             y: endPt1.y - basePt.y
92549           };
92550           var v2 = {
92551             x: endPt2.x - basePt.x,
92552             y: endPt2.y - basePt.y
92553           };
92554           var kross = crossProduct$1(v1, v2);
92555           return cmp(kross, 0);
92556         };
92557
92558         var length = function length(v) {
92559           return Math.sqrt(dotProduct$1(v, v));
92560         };
92561         /* Get the sine of the angle from pShared -> pAngle to pShaed -> pBase */
92562
92563
92564         var sineOfAngle = function sineOfAngle(pShared, pBase, pAngle) {
92565           var vBase = {
92566             x: pBase.x - pShared.x,
92567             y: pBase.y - pShared.y
92568           };
92569           var vAngle = {
92570             x: pAngle.x - pShared.x,
92571             y: pAngle.y - pShared.y
92572           };
92573           return crossProduct$1(vAngle, vBase) / length(vAngle) / length(vBase);
92574         };
92575         /* Get the cosine of the angle from pShared -> pAngle to pShaed -> pBase */
92576
92577
92578         var cosineOfAngle = function cosineOfAngle(pShared, pBase, pAngle) {
92579           var vBase = {
92580             x: pBase.x - pShared.x,
92581             y: pBase.y - pShared.y
92582           };
92583           var vAngle = {
92584             x: pAngle.x - pShared.x,
92585             y: pAngle.y - pShared.y
92586           };
92587           return dotProduct$1(vAngle, vBase) / length(vAngle) / length(vBase);
92588         };
92589         /* Get the x coordinate where the given line (defined by a point and vector)
92590          * crosses the horizontal line with the given y coordiante.
92591          * In the case of parrallel lines (including overlapping ones) returns null. */
92592
92593
92594         var horizontalIntersection = function horizontalIntersection(pt, v, y) {
92595           if (v.y === 0) return null;
92596           return {
92597             x: pt.x + v.x / v.y * (y - pt.y),
92598             y: y
92599           };
92600         };
92601         /* Get the y coordinate where the given line (defined by a point and vector)
92602          * crosses the vertical line with the given x coordiante.
92603          * In the case of parrallel lines (including overlapping ones) returns null. */
92604
92605
92606         var verticalIntersection = function verticalIntersection(pt, v, x) {
92607           if (v.x === 0) return null;
92608           return {
92609             x: x,
92610             y: pt.y + v.y / v.x * (x - pt.x)
92611           };
92612         };
92613         /* Get the intersection of two lines, each defined by a base point and a vector.
92614          * In the case of parrallel lines (including overlapping ones) returns null. */
92615
92616
92617         var intersection$1 = function intersection(pt1, v1, pt2, v2) {
92618           // take some shortcuts for vertical and horizontal lines
92619           // this also ensures we don't calculate an intersection and then discover
92620           // it's actually outside the bounding box of the line
92621           if (v1.x === 0) return verticalIntersection(pt2, v2, pt1.x);
92622           if (v2.x === 0) return verticalIntersection(pt1, v1, pt2.x);
92623           if (v1.y === 0) return horizontalIntersection(pt2, v2, pt1.y);
92624           if (v2.y === 0) return horizontalIntersection(pt1, v1, pt2.y); // General case for non-overlapping segments.
92625           // This algorithm is based on Schneider and Eberly.
92626           // http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf - pg 244
92627
92628           var kross = crossProduct$1(v1, v2);
92629           if (kross == 0) return null;
92630           var ve = {
92631             x: pt2.x - pt1.x,
92632             y: pt2.y - pt1.y
92633           };
92634           var d1 = crossProduct$1(ve, v1) / kross;
92635           var d2 = crossProduct$1(ve, v2) / kross; // take the average of the two calculations to minimize rounding error
92636
92637           var x1 = pt1.x + d2 * v1.x,
92638               x2 = pt2.x + d1 * v2.x;
92639           var y1 = pt1.y + d2 * v1.y,
92640               y2 = pt2.y + d1 * v2.y;
92641           var x = (x1 + x2) / 2;
92642           var y = (y1 + y2) / 2;
92643           return {
92644             x: x,
92645             y: y
92646           };
92647         };
92648
92649         var SweepEvent$1 = /*#__PURE__*/function () {
92650           _createClass$1(SweepEvent, null, [{
92651             key: "compare",
92652             // for ordering sweep events in the sweep event queue
92653             value: function compare(a, b) {
92654               // favor event with a point that the sweep line hits first
92655               var ptCmp = SweepEvent.comparePoints(a.point, b.point);
92656               if (ptCmp !== 0) return ptCmp; // the points are the same, so link them if needed
92657
92658               if (a.point !== b.point) a.link(b); // favor right events over left
92659
92660               if (a.isLeft !== b.isLeft) return a.isLeft ? 1 : -1; // we have two matching left or right endpoints
92661               // ordering of this case is the same as for their segments
92662
92663               return Segment.compare(a.segment, b.segment);
92664             } // for ordering points in sweep line order
92665
92666           }, {
92667             key: "comparePoints",
92668             value: function comparePoints(aPt, bPt) {
92669               if (aPt.x < bPt.x) return -1;
92670               if (aPt.x > bPt.x) return 1;
92671               if (aPt.y < bPt.y) return -1;
92672               if (aPt.y > bPt.y) return 1;
92673               return 0;
92674             } // Warning: 'point' input will be modified and re-used (for performance)
92675
92676           }]);
92677
92678           function SweepEvent(point, isLeft) {
92679             _classCallCheck$1(this, SweepEvent);
92680
92681             if (point.events === undefined) point.events = [this];else point.events.push(this);
92682             this.point = point;
92683             this.isLeft = isLeft; // this.segment, this.otherSE set by factory
92684           }
92685
92686           _createClass$1(SweepEvent, [{
92687             key: "link",
92688             value: function link(other) {
92689               if (other.point === this.point) {
92690                 throw new Error('Tried to link already linked events');
92691               }
92692
92693               var otherEvents = other.point.events;
92694
92695               for (var i = 0, iMax = otherEvents.length; i < iMax; i++) {
92696                 var evt = otherEvents[i];
92697                 this.point.events.push(evt);
92698                 evt.point = this.point;
92699               }
92700
92701               this.checkForConsuming();
92702             }
92703             /* Do a pass over our linked events and check to see if any pair
92704              * of segments match, and should be consumed. */
92705
92706           }, {
92707             key: "checkForConsuming",
92708             value: function checkForConsuming() {
92709               // FIXME: The loops in this method run O(n^2) => no good.
92710               //        Maintain little ordered sweep event trees?
92711               //        Can we maintaining an ordering that avoids the need
92712               //        for the re-sorting with getLeftmostComparator in geom-out?
92713               // Compare each pair of events to see if other events also match
92714               var numEvents = this.point.events.length;
92715
92716               for (var i = 0; i < numEvents; i++) {
92717                 var evt1 = this.point.events[i];
92718                 if (evt1.segment.consumedBy !== undefined) continue;
92719
92720                 for (var j = i + 1; j < numEvents; j++) {
92721                   var evt2 = this.point.events[j];
92722                   if (evt2.consumedBy !== undefined) continue;
92723                   if (evt1.otherSE.point.events !== evt2.otherSE.point.events) continue;
92724                   evt1.segment.consume(evt2.segment);
92725                 }
92726               }
92727             }
92728           }, {
92729             key: "getAvailableLinkedEvents",
92730             value: function getAvailableLinkedEvents() {
92731               // point.events is always of length 2 or greater
92732               var events = [];
92733
92734               for (var i = 0, iMax = this.point.events.length; i < iMax; i++) {
92735                 var evt = this.point.events[i];
92736
92737                 if (evt !== this && !evt.segment.ringOut && evt.segment.isInResult()) {
92738                   events.push(evt);
92739                 }
92740               }
92741
92742               return events;
92743             }
92744             /**
92745              * Returns a comparator function for sorting linked events that will
92746              * favor the event that will give us the smallest left-side angle.
92747              * All ring construction starts as low as possible heading to the right,
92748              * so by always turning left as sharp as possible we'll get polygons
92749              * without uncessary loops & holes.
92750              *
92751              * The comparator function has a compute cache such that it avoids
92752              * re-computing already-computed values.
92753              */
92754
92755           }, {
92756             key: "getLeftmostComparator",
92757             value: function getLeftmostComparator(baseEvent) {
92758               var _this = this;
92759
92760               var cache = new Map();
92761
92762               var fillCache = function fillCache(linkedEvent) {
92763                 var nextEvent = linkedEvent.otherSE;
92764                 cache.set(linkedEvent, {
92765                   sine: sineOfAngle(_this.point, baseEvent.point, nextEvent.point),
92766                   cosine: cosineOfAngle(_this.point, baseEvent.point, nextEvent.point)
92767                 });
92768               };
92769
92770               return function (a, b) {
92771                 if (!cache.has(a)) fillCache(a);
92772                 if (!cache.has(b)) fillCache(b);
92773
92774                 var _cache$get = cache.get(a),
92775                     asine = _cache$get.sine,
92776                     acosine = _cache$get.cosine;
92777
92778                 var _cache$get2 = cache.get(b),
92779                     bsine = _cache$get2.sine,
92780                     bcosine = _cache$get2.cosine; // both on or above x-axis
92781
92782
92783                 if (asine >= 0 && bsine >= 0) {
92784                   if (acosine < bcosine) return 1;
92785                   if (acosine > bcosine) return -1;
92786                   return 0;
92787                 } // both below x-axis
92788
92789
92790                 if (asine < 0 && bsine < 0) {
92791                   if (acosine < bcosine) return -1;
92792                   if (acosine > bcosine) return 1;
92793                   return 0;
92794                 } // one above x-axis, one below
92795
92796
92797                 if (bsine < asine) return -1;
92798                 if (bsine > asine) return 1;
92799                 return 0;
92800               };
92801             }
92802           }]);
92803
92804           return SweepEvent;
92805         }(); // segments and sweep events when all else is identical
92806
92807
92808         var segmentId = 0;
92809
92810         var Segment = /*#__PURE__*/function () {
92811           _createClass$1(Segment, null, [{
92812             key: "compare",
92813
92814             /* This compare() function is for ordering segments in the sweep
92815              * line tree, and does so according to the following criteria:
92816              *
92817              * Consider the vertical line that lies an infinestimal step to the
92818              * right of the right-more of the two left endpoints of the input
92819              * segments. Imagine slowly moving a point up from negative infinity
92820              * in the increasing y direction. Which of the two segments will that
92821              * point intersect first? That segment comes 'before' the other one.
92822              *
92823              * If neither segment would be intersected by such a line, (if one
92824              * or more of the segments are vertical) then the line to be considered
92825              * is directly on the right-more of the two left inputs.
92826              */
92827             value: function compare(a, b) {
92828               var alx = a.leftSE.point.x;
92829               var blx = b.leftSE.point.x;
92830               var arx = a.rightSE.point.x;
92831               var brx = b.rightSE.point.x; // check if they're even in the same vertical plane
92832
92833               if (brx < alx) return 1;
92834               if (arx < blx) return -1;
92835               var aly = a.leftSE.point.y;
92836               var bly = b.leftSE.point.y;
92837               var ary = a.rightSE.point.y;
92838               var bry = b.rightSE.point.y; // is left endpoint of segment B the right-more?
92839
92840               if (alx < blx) {
92841                 // are the two segments in the same horizontal plane?
92842                 if (bly < aly && bly < ary) return 1;
92843                 if (bly > aly && bly > ary) return -1; // is the B left endpoint colinear to segment A?
92844
92845                 var aCmpBLeft = a.comparePoint(b.leftSE.point);
92846                 if (aCmpBLeft < 0) return 1;
92847                 if (aCmpBLeft > 0) return -1; // is the A right endpoint colinear to segment B ?
92848
92849                 var bCmpARight = b.comparePoint(a.rightSE.point);
92850                 if (bCmpARight !== 0) return bCmpARight; // colinear segments, consider the one with left-more
92851                 // left endpoint to be first (arbitrary?)
92852
92853                 return -1;
92854               } // is left endpoint of segment A the right-more?
92855
92856
92857               if (alx > blx) {
92858                 if (aly < bly && aly < bry) return -1;
92859                 if (aly > bly && aly > bry) return 1; // is the A left endpoint colinear to segment B?
92860
92861                 var bCmpALeft = b.comparePoint(a.leftSE.point);
92862                 if (bCmpALeft !== 0) return bCmpALeft; // is the B right endpoint colinear to segment A?
92863
92864                 var aCmpBRight = a.comparePoint(b.rightSE.point);
92865                 if (aCmpBRight < 0) return 1;
92866                 if (aCmpBRight > 0) return -1; // colinear segments, consider the one with left-more
92867                 // left endpoint to be first (arbitrary?)
92868
92869                 return 1;
92870               } // if we get here, the two left endpoints are in the same
92871               // vertical plane, ie alx === blx
92872               // consider the lower left-endpoint to come first
92873
92874
92875               if (aly < bly) return -1;
92876               if (aly > bly) return 1; // left endpoints are identical
92877               // check for colinearity by using the left-more right endpoint
92878               // is the A right endpoint more left-more?
92879
92880               if (arx < brx) {
92881                 var _bCmpARight = b.comparePoint(a.rightSE.point);
92882
92883                 if (_bCmpARight !== 0) return _bCmpARight;
92884               } // is the B right endpoint more left-more?
92885
92886
92887               if (arx > brx) {
92888                 var _aCmpBRight = a.comparePoint(b.rightSE.point);
92889
92890                 if (_aCmpBRight < 0) return 1;
92891                 if (_aCmpBRight > 0) return -1;
92892               }
92893
92894               if (arx !== brx) {
92895                 // are these two [almost] vertical segments with opposite orientation?
92896                 // if so, the one with the lower right endpoint comes first
92897                 var ay = ary - aly;
92898                 var ax = arx - alx;
92899                 var by = bry - bly;
92900                 var bx = brx - blx;
92901                 if (ay > ax && by < bx) return 1;
92902                 if (ay < ax && by > bx) return -1;
92903               } // we have colinear segments with matching orientation
92904               // consider the one with more left-more right endpoint to be first
92905
92906
92907               if (arx > brx) return 1;
92908               if (arx < brx) return -1; // if we get here, two two right endpoints are in the same
92909               // vertical plane, ie arx === brx
92910               // consider the lower right-endpoint to come first
92911
92912               if (ary < bry) return -1;
92913               if (ary > bry) return 1; // right endpoints identical as well, so the segments are idential
92914               // fall back on creation order as consistent tie-breaker
92915
92916               if (a.id < b.id) return -1;
92917               if (a.id > b.id) return 1; // identical segment, ie a === b
92918
92919               return 0;
92920             }
92921             /* Warning: a reference to ringWindings input will be stored,
92922              *  and possibly will be later modified */
92923
92924           }]);
92925
92926           function Segment(leftSE, rightSE, rings, windings) {
92927             _classCallCheck$1(this, Segment);
92928
92929             this.id = ++segmentId;
92930             this.leftSE = leftSE;
92931             leftSE.segment = this;
92932             leftSE.otherSE = rightSE;
92933             this.rightSE = rightSE;
92934             rightSE.segment = this;
92935             rightSE.otherSE = leftSE;
92936             this.rings = rings;
92937             this.windings = windings; // left unset for performance, set later in algorithm
92938             // this.ringOut, this.consumedBy, this.prev
92939           }
92940
92941           _createClass$1(Segment, [{
92942             key: "replaceRightSE",
92943
92944             /* When a segment is split, the rightSE is replaced with a new sweep event */
92945             value: function replaceRightSE(newRightSE) {
92946               this.rightSE = newRightSE;
92947               this.rightSE.segment = this;
92948               this.rightSE.otherSE = this.leftSE;
92949               this.leftSE.otherSE = this.rightSE;
92950             }
92951           }, {
92952             key: "bbox",
92953             value: function bbox() {
92954               var y1 = this.leftSE.point.y;
92955               var y2 = this.rightSE.point.y;
92956               return {
92957                 ll: {
92958                   x: this.leftSE.point.x,
92959                   y: y1 < y2 ? y1 : y2
92960                 },
92961                 ur: {
92962                   x: this.rightSE.point.x,
92963                   y: y1 > y2 ? y1 : y2
92964                 }
92965               };
92966             }
92967             /* A vector from the left point to the right */
92968
92969           }, {
92970             key: "vector",
92971             value: function vector() {
92972               return {
92973                 x: this.rightSE.point.x - this.leftSE.point.x,
92974                 y: this.rightSE.point.y - this.leftSE.point.y
92975               };
92976             }
92977           }, {
92978             key: "isAnEndpoint",
92979             value: function isAnEndpoint(pt) {
92980               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;
92981             }
92982             /* Compare this segment with a point.
92983              *
92984              * A point P is considered to be colinear to a segment if there
92985              * exists a distance D such that if we travel along the segment
92986              * from one * endpoint towards the other a distance D, we find
92987              * ourselves at point P.
92988              *
92989              * Return value indicates:
92990              *
92991              *   1: point lies above the segment (to the left of vertical)
92992              *   0: point is colinear to segment
92993              *  -1: point lies below the segment (to the right of vertical)
92994              */
92995
92996           }, {
92997             key: "comparePoint",
92998             value: function comparePoint(point) {
92999               if (this.isAnEndpoint(point)) return 0;
93000               var lPt = this.leftSE.point;
93001               var rPt = this.rightSE.point;
93002               var v = this.vector(); // Exactly vertical segments.
93003
93004               if (lPt.x === rPt.x) {
93005                 if (point.x === lPt.x) return 0;
93006                 return point.x < lPt.x ? 1 : -1;
93007               } // Nearly vertical segments with an intersection.
93008               // Check to see where a point on the line with matching Y coordinate is.
93009
93010
93011               var yDist = (point.y - lPt.y) / v.y;
93012               var xFromYDist = lPt.x + yDist * v.x;
93013               if (point.x === xFromYDist) return 0; // General case.
93014               // Check to see where a point on the line with matching X coordinate is.
93015
93016               var xDist = (point.x - lPt.x) / v.x;
93017               var yFromXDist = lPt.y + xDist * v.y;
93018               if (point.y === yFromXDist) return 0;
93019               return point.y < yFromXDist ? -1 : 1;
93020             }
93021             /**
93022              * Given another segment, returns the first non-trivial intersection
93023              * between the two segments (in terms of sweep line ordering), if it exists.
93024              *
93025              * A 'non-trivial' intersection is one that will cause one or both of the
93026              * segments to be split(). As such, 'trivial' vs. 'non-trivial' intersection:
93027              *
93028              *   * endpoint of segA with endpoint of segB --> trivial
93029              *   * endpoint of segA with point along segB --> non-trivial
93030              *   * endpoint of segB with point along segA --> non-trivial
93031              *   * point along segA with point along segB --> non-trivial
93032              *
93033              * If no non-trivial intersection exists, return null
93034              * Else, return null.
93035              */
93036
93037           }, {
93038             key: "getIntersection",
93039             value: function getIntersection(other) {
93040               // If bboxes don't overlap, there can't be any intersections
93041               var tBbox = this.bbox();
93042               var oBbox = other.bbox();
93043               var bboxOverlap = getBboxOverlap(tBbox, oBbox);
93044               if (bboxOverlap === null) return null; // We first check to see if the endpoints can be considered intersections.
93045               // This will 'snap' intersections to endpoints if possible, and will
93046               // handle cases of colinearity.
93047
93048               var tlp = this.leftSE.point;
93049               var trp = this.rightSE.point;
93050               var olp = other.leftSE.point;
93051               var orp = other.rightSE.point; // does each endpoint touch the other segment?
93052               // note that we restrict the 'touching' definition to only allow segments
93053               // to touch endpoints that lie forward from where we are in the sweep line pass
93054
93055               var touchesOtherLSE = isInBbox(tBbox, olp) && this.comparePoint(olp) === 0;
93056               var touchesThisLSE = isInBbox(oBbox, tlp) && other.comparePoint(tlp) === 0;
93057               var touchesOtherRSE = isInBbox(tBbox, orp) && this.comparePoint(orp) === 0;
93058               var touchesThisRSE = isInBbox(oBbox, trp) && other.comparePoint(trp) === 0; // do left endpoints match?
93059
93060               if (touchesThisLSE && touchesOtherLSE) {
93061                 // these two cases are for colinear segments with matching left
93062                 // endpoints, and one segment being longer than the other
93063                 if (touchesThisRSE && !touchesOtherRSE) return trp;
93064                 if (!touchesThisRSE && touchesOtherRSE) return orp; // either the two segments match exactly (two trival intersections)
93065                 // or just on their left endpoint (one trivial intersection
93066
93067                 return null;
93068               } // does this left endpoint matches (other doesn't)
93069
93070
93071               if (touchesThisLSE) {
93072                 // check for segments that just intersect on opposing endpoints
93073                 if (touchesOtherRSE) {
93074                   if (tlp.x === orp.x && tlp.y === orp.y) return null;
93075                 } // t-intersection on left endpoint
93076
93077
93078                 return tlp;
93079               } // does other left endpoint matches (this doesn't)
93080
93081
93082               if (touchesOtherLSE) {
93083                 // check for segments that just intersect on opposing endpoints
93084                 if (touchesThisRSE) {
93085                   if (trp.x === olp.x && trp.y === olp.y) return null;
93086                 } // t-intersection on left endpoint
93087
93088
93089                 return olp;
93090               } // trivial intersection on right endpoints
93091
93092
93093               if (touchesThisRSE && touchesOtherRSE) return null; // t-intersections on just one right endpoint
93094
93095               if (touchesThisRSE) return trp;
93096               if (touchesOtherRSE) return orp; // None of our endpoints intersect. Look for a general intersection between
93097               // infinite lines laid over the segments
93098
93099               var pt = intersection$1(tlp, this.vector(), olp, other.vector()); // are the segments parrallel? Note that if they were colinear with overlap,
93100               // they would have an endpoint intersection and that case was already handled above
93101
93102               if (pt === null) return null; // is the intersection found between the lines not on the segments?
93103
93104               if (!isInBbox(bboxOverlap, pt)) return null; // round the the computed point if needed
93105
93106               return rounder.round(pt.x, pt.y);
93107             }
93108             /**
93109              * Split the given segment into multiple segments on the given points.
93110              *  * Each existing segment will retain its leftSE and a new rightSE will be
93111              *    generated for it.
93112              *  * A new segment will be generated which will adopt the original segment's
93113              *    rightSE, and a new leftSE will be generated for it.
93114              *  * If there are more than two points given to split on, new segments
93115              *    in the middle will be generated with new leftSE and rightSE's.
93116              *  * An array of the newly generated SweepEvents will be returned.
93117              *
93118              * Warning: input array of points is modified
93119              */
93120
93121           }, {
93122             key: "split",
93123             value: function split(point) {
93124               var newEvents = [];
93125               var alreadyLinked = point.events !== undefined;
93126               var newLeftSE = new SweepEvent$1(point, true);
93127               var newRightSE = new SweepEvent$1(point, false);
93128               var oldRightSE = this.rightSE;
93129               this.replaceRightSE(newRightSE);
93130               newEvents.push(newRightSE);
93131               newEvents.push(newLeftSE);
93132               var newSeg = new Segment(newLeftSE, oldRightSE, this.rings.slice(), this.windings.slice()); // when splitting a nearly vertical downward-facing segment,
93133               // sometimes one of the resulting new segments is vertical, in which
93134               // case its left and right events may need to be swapped
93135
93136               if (SweepEvent$1.comparePoints(newSeg.leftSE.point, newSeg.rightSE.point) > 0) {
93137                 newSeg.swapEvents();
93138               }
93139
93140               if (SweepEvent$1.comparePoints(this.leftSE.point, this.rightSE.point) > 0) {
93141                 this.swapEvents();
93142               } // in the point we just used to create new sweep events with was already
93143               // linked to other events, we need to check if either of the affected
93144               // segments should be consumed
93145
93146
93147               if (alreadyLinked) {
93148                 newLeftSE.checkForConsuming();
93149                 newRightSE.checkForConsuming();
93150               }
93151
93152               return newEvents;
93153             }
93154             /* Swap which event is left and right */
93155
93156           }, {
93157             key: "swapEvents",
93158             value: function swapEvents() {
93159               var tmpEvt = this.rightSE;
93160               this.rightSE = this.leftSE;
93161               this.leftSE = tmpEvt;
93162               this.leftSE.isLeft = true;
93163               this.rightSE.isLeft = false;
93164
93165               for (var i = 0, iMax = this.windings.length; i < iMax; i++) {
93166                 this.windings[i] *= -1;
93167               }
93168             }
93169             /* Consume another segment. We take their rings under our wing
93170              * and mark them as consumed. Use for perfectly overlapping segments */
93171
93172           }, {
93173             key: "consume",
93174             value: function consume(other) {
93175               var consumer = this;
93176               var consumee = other;
93177
93178               while (consumer.consumedBy) {
93179                 consumer = consumer.consumedBy;
93180               }
93181
93182               while (consumee.consumedBy) {
93183                 consumee = consumee.consumedBy;
93184               }
93185
93186               var cmp = Segment.compare(consumer, consumee);
93187               if (cmp === 0) return; // already consumed
93188               // the winner of the consumption is the earlier segment
93189               // according to sweep line ordering
93190
93191               if (cmp > 0) {
93192                 var tmp = consumer;
93193                 consumer = consumee;
93194                 consumee = tmp;
93195               } // make sure a segment doesn't consume it's prev
93196
93197
93198               if (consumer.prev === consumee) {
93199                 var _tmp = consumer;
93200                 consumer = consumee;
93201                 consumee = _tmp;
93202               }
93203
93204               for (var i = 0, iMax = consumee.rings.length; i < iMax; i++) {
93205                 var ring = consumee.rings[i];
93206                 var winding = consumee.windings[i];
93207                 var index = consumer.rings.indexOf(ring);
93208
93209                 if (index === -1) {
93210                   consumer.rings.push(ring);
93211                   consumer.windings.push(winding);
93212                 } else consumer.windings[index] += winding;
93213               }
93214
93215               consumee.rings = null;
93216               consumee.windings = null;
93217               consumee.consumedBy = consumer; // mark sweep events consumed as to maintain ordering in sweep event queue
93218
93219               consumee.leftSE.consumedBy = consumer.leftSE;
93220               consumee.rightSE.consumedBy = consumer.rightSE;
93221             }
93222             /* The first segment previous segment chain that is in the result */
93223
93224           }, {
93225             key: "prevInResult",
93226             value: function prevInResult() {
93227               if (this._prevInResult !== undefined) return this._prevInResult;
93228               if (!this.prev) this._prevInResult = null;else if (this.prev.isInResult()) this._prevInResult = this.prev;else this._prevInResult = this.prev.prevInResult();
93229               return this._prevInResult;
93230             }
93231           }, {
93232             key: "beforeState",
93233             value: function beforeState() {
93234               if (this._beforeState !== undefined) return this._beforeState;
93235               if (!this.prev) this._beforeState = {
93236                 rings: [],
93237                 windings: [],
93238                 multiPolys: []
93239               };else {
93240                 var seg = this.prev.consumedBy || this.prev;
93241                 this._beforeState = seg.afterState();
93242               }
93243               return this._beforeState;
93244             }
93245           }, {
93246             key: "afterState",
93247             value: function afterState() {
93248               if (this._afterState !== undefined) return this._afterState;
93249               var beforeState = this.beforeState();
93250               this._afterState = {
93251                 rings: beforeState.rings.slice(0),
93252                 windings: beforeState.windings.slice(0),
93253                 multiPolys: []
93254               };
93255               var ringsAfter = this._afterState.rings;
93256               var windingsAfter = this._afterState.windings;
93257               var mpsAfter = this._afterState.multiPolys; // calculate ringsAfter, windingsAfter
93258
93259               for (var i = 0, iMax = this.rings.length; i < iMax; i++) {
93260                 var ring = this.rings[i];
93261                 var winding = this.windings[i];
93262                 var index = ringsAfter.indexOf(ring);
93263
93264                 if (index === -1) {
93265                   ringsAfter.push(ring);
93266                   windingsAfter.push(winding);
93267                 } else windingsAfter[index] += winding;
93268               } // calcualte polysAfter
93269
93270
93271               var polysAfter = [];
93272               var polysExclude = [];
93273
93274               for (var _i = 0, _iMax = ringsAfter.length; _i < _iMax; _i++) {
93275                 if (windingsAfter[_i] === 0) continue; // non-zero rule
93276
93277                 var _ring = ringsAfter[_i];
93278                 var poly = _ring.poly;
93279                 if (polysExclude.indexOf(poly) !== -1) continue;
93280                 if (_ring.isExterior) polysAfter.push(poly);else {
93281                   if (polysExclude.indexOf(poly) === -1) polysExclude.push(poly);
93282
93283                   var _index = polysAfter.indexOf(_ring.poly);
93284
93285                   if (_index !== -1) polysAfter.splice(_index, 1);
93286                 }
93287               } // calculate multiPolysAfter
93288
93289
93290               for (var _i2 = 0, _iMax2 = polysAfter.length; _i2 < _iMax2; _i2++) {
93291                 var mp = polysAfter[_i2].multiPoly;
93292                 if (mpsAfter.indexOf(mp) === -1) mpsAfter.push(mp);
93293               }
93294
93295               return this._afterState;
93296             }
93297             /* Is this segment part of the final result? */
93298
93299           }, {
93300             key: "isInResult",
93301             value: function isInResult() {
93302               // if we've been consumed, we're not in the result
93303               if (this.consumedBy) return false;
93304               if (this._isInResult !== undefined) return this._isInResult;
93305               var mpsBefore = this.beforeState().multiPolys;
93306               var mpsAfter = this.afterState().multiPolys;
93307
93308               switch (operation.type) {
93309                 case 'union':
93310                   {
93311                     // UNION - included iff:
93312                     //  * On one side of us there is 0 poly interiors AND
93313                     //  * On the other side there is 1 or more.
93314                     var noBefores = mpsBefore.length === 0;
93315                     var noAfters = mpsAfter.length === 0;
93316                     this._isInResult = noBefores !== noAfters;
93317                     break;
93318                   }
93319
93320                 case 'intersection':
93321                   {
93322                     // INTERSECTION - included iff:
93323                     //  * on one side of us all multipolys are rep. with poly interiors AND
93324                     //  * on the other side of us, not all multipolys are repsented
93325                     //    with poly interiors
93326                     var least;
93327                     var most;
93328
93329                     if (mpsBefore.length < mpsAfter.length) {
93330                       least = mpsBefore.length;
93331                       most = mpsAfter.length;
93332                     } else {
93333                       least = mpsAfter.length;
93334                       most = mpsBefore.length;
93335                     }
93336
93337                     this._isInResult = most === operation.numMultiPolys && least < most;
93338                     break;
93339                   }
93340
93341                 case 'xor':
93342                   {
93343                     // XOR - included iff:
93344                     //  * the difference between the number of multipolys represented
93345                     //    with poly interiors on our two sides is an odd number
93346                     var diff = Math.abs(mpsBefore.length - mpsAfter.length);
93347                     this._isInResult = diff % 2 === 1;
93348                     break;
93349                   }
93350
93351                 case 'difference':
93352                   {
93353                     // DIFFERENCE included iff:
93354                     //  * on exactly one side, we have just the subject
93355                     var isJustSubject = function isJustSubject(mps) {
93356                       return mps.length === 1 && mps[0].isSubject;
93357                     };
93358
93359                     this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
93360                     break;
93361                   }
93362
93363                 default:
93364                   throw new Error("Unrecognized operation type found ".concat(operation.type));
93365               }
93366
93367               return this._isInResult;
93368             }
93369           }], [{
93370             key: "fromRing",
93371             value: function fromRing(pt1, pt2, ring) {
93372               var leftPt, rightPt, winding; // ordering the two points according to sweep line ordering
93373
93374               var cmpPts = SweepEvent$1.comparePoints(pt1, pt2);
93375
93376               if (cmpPts < 0) {
93377                 leftPt = pt1;
93378                 rightPt = pt2;
93379                 winding = 1;
93380               } else if (cmpPts > 0) {
93381                 leftPt = pt2;
93382                 rightPt = pt1;
93383                 winding = -1;
93384               } else throw new Error("Tried to create degenerate segment at [".concat(pt1.x, ", ").concat(pt1.y, "]"));
93385
93386               var leftSE = new SweepEvent$1(leftPt, true);
93387               var rightSE = new SweepEvent$1(rightPt, false);
93388               return new Segment(leftSE, rightSE, [ring], [winding]);
93389             }
93390           }]);
93391
93392           return Segment;
93393         }();
93394
93395         var RingIn = /*#__PURE__*/function () {
93396           function RingIn(geomRing, poly, isExterior) {
93397             _classCallCheck$1(this, RingIn);
93398
93399             if (!Array.isArray(geomRing) || geomRing.length === 0) {
93400               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
93401             }
93402
93403             this.poly = poly;
93404             this.isExterior = isExterior;
93405             this.segments = [];
93406
93407             if (typeof geomRing[0][0] !== 'number' || typeof geomRing[0][1] !== 'number') {
93408               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
93409             }
93410
93411             var firstPoint = rounder.round(geomRing[0][0], geomRing[0][1]);
93412             this.bbox = {
93413               ll: {
93414                 x: firstPoint.x,
93415                 y: firstPoint.y
93416               },
93417               ur: {
93418                 x: firstPoint.x,
93419                 y: firstPoint.y
93420               }
93421             };
93422             var prevPoint = firstPoint;
93423
93424             for (var i = 1, iMax = geomRing.length; i < iMax; i++) {
93425               if (typeof geomRing[i][0] !== 'number' || typeof geomRing[i][1] !== 'number') {
93426                 throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
93427               }
93428
93429               var point = rounder.round(geomRing[i][0], geomRing[i][1]); // skip repeated points
93430
93431               if (point.x === prevPoint.x && point.y === prevPoint.y) continue;
93432               this.segments.push(Segment.fromRing(prevPoint, point, this));
93433               if (point.x < this.bbox.ll.x) this.bbox.ll.x = point.x;
93434               if (point.y < this.bbox.ll.y) this.bbox.ll.y = point.y;
93435               if (point.x > this.bbox.ur.x) this.bbox.ur.x = point.x;
93436               if (point.y > this.bbox.ur.y) this.bbox.ur.y = point.y;
93437               prevPoint = point;
93438             } // add segment from last to first if last is not the same as first
93439
93440
93441             if (firstPoint.x !== prevPoint.x || firstPoint.y !== prevPoint.y) {
93442               this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
93443             }
93444           }
93445
93446           _createClass$1(RingIn, [{
93447             key: "getSweepEvents",
93448             value: function getSweepEvents() {
93449               var sweepEvents = [];
93450
93451               for (var i = 0, iMax = this.segments.length; i < iMax; i++) {
93452                 var segment = this.segments[i];
93453                 sweepEvents.push(segment.leftSE);
93454                 sweepEvents.push(segment.rightSE);
93455               }
93456
93457               return sweepEvents;
93458             }
93459           }]);
93460
93461           return RingIn;
93462         }();
93463
93464         var PolyIn = /*#__PURE__*/function () {
93465           function PolyIn(geomPoly, multiPoly) {
93466             _classCallCheck$1(this, PolyIn);
93467
93468             if (!Array.isArray(geomPoly)) {
93469               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
93470             }
93471
93472             this.exteriorRing = new RingIn(geomPoly[0], this, true); // copy by value
93473
93474             this.bbox = {
93475               ll: {
93476                 x: this.exteriorRing.bbox.ll.x,
93477                 y: this.exteriorRing.bbox.ll.y
93478               },
93479               ur: {
93480                 x: this.exteriorRing.bbox.ur.x,
93481                 y: this.exteriorRing.bbox.ur.y
93482               }
93483             };
93484             this.interiorRings = [];
93485
93486             for (var i = 1, iMax = geomPoly.length; i < iMax; i++) {
93487               var ring = new RingIn(geomPoly[i], this, false);
93488               if (ring.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = ring.bbox.ll.x;
93489               if (ring.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = ring.bbox.ll.y;
93490               if (ring.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = ring.bbox.ur.x;
93491               if (ring.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = ring.bbox.ur.y;
93492               this.interiorRings.push(ring);
93493             }
93494
93495             this.multiPoly = multiPoly;
93496           }
93497
93498           _createClass$1(PolyIn, [{
93499             key: "getSweepEvents",
93500             value: function getSweepEvents() {
93501               var sweepEvents = this.exteriorRing.getSweepEvents();
93502
93503               for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
93504                 var ringSweepEvents = this.interiorRings[i].getSweepEvents();
93505
93506                 for (var j = 0, jMax = ringSweepEvents.length; j < jMax; j++) {
93507                   sweepEvents.push(ringSweepEvents[j]);
93508                 }
93509               }
93510
93511               return sweepEvents;
93512             }
93513           }]);
93514
93515           return PolyIn;
93516         }();
93517
93518         var MultiPolyIn = /*#__PURE__*/function () {
93519           function MultiPolyIn(geom, isSubject) {
93520             _classCallCheck$1(this, MultiPolyIn);
93521
93522             if (!Array.isArray(geom)) {
93523               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
93524             }
93525
93526             try {
93527               // if the input looks like a polygon, convert it to a multipolygon
93528               if (typeof geom[0][0][0] === 'number') geom = [geom];
93529             } catch (ex) {// The input is either malformed or has empty arrays.
93530               // In either case, it will be handled later on.
93531             }
93532
93533             this.polys = [];
93534             this.bbox = {
93535               ll: {
93536                 x: Number.POSITIVE_INFINITY,
93537                 y: Number.POSITIVE_INFINITY
93538               },
93539               ur: {
93540                 x: Number.NEGATIVE_INFINITY,
93541                 y: Number.NEGATIVE_INFINITY
93542               }
93543             };
93544
93545             for (var i = 0, iMax = geom.length; i < iMax; i++) {
93546               var poly = new PolyIn(geom[i], this);
93547               if (poly.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = poly.bbox.ll.x;
93548               if (poly.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = poly.bbox.ll.y;
93549               if (poly.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = poly.bbox.ur.x;
93550               if (poly.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = poly.bbox.ur.y;
93551               this.polys.push(poly);
93552             }
93553
93554             this.isSubject = isSubject;
93555           }
93556
93557           _createClass$1(MultiPolyIn, [{
93558             key: "getSweepEvents",
93559             value: function getSweepEvents() {
93560               var sweepEvents = [];
93561
93562               for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
93563                 var polySweepEvents = this.polys[i].getSweepEvents();
93564
93565                 for (var j = 0, jMax = polySweepEvents.length; j < jMax; j++) {
93566                   sweepEvents.push(polySweepEvents[j]);
93567                 }
93568               }
93569
93570               return sweepEvents;
93571             }
93572           }]);
93573
93574           return MultiPolyIn;
93575         }();
93576
93577         var RingOut = /*#__PURE__*/function () {
93578           _createClass$1(RingOut, null, [{
93579             key: "factory",
93580
93581             /* Given the segments from the sweep line pass, compute & return a series
93582              * of closed rings from all the segments marked to be part of the result */
93583             value: function factory(allSegments) {
93584               var ringsOut = [];
93585
93586               for (var i = 0, iMax = allSegments.length; i < iMax; i++) {
93587                 var segment = allSegments[i];
93588                 if (!segment.isInResult() || segment.ringOut) continue;
93589                 var prevEvent = null;
93590                 var event = segment.leftSE;
93591                 var nextEvent = segment.rightSE;
93592                 var events = [event];
93593                 var startingPoint = event.point;
93594                 var intersectionLEs = [];
93595                 /* Walk the chain of linked events to form a closed ring */
93596
93597                 while (true) {
93598                   prevEvent = event;
93599                   event = nextEvent;
93600                   events.push(event);
93601                   /* Is the ring complete? */
93602
93603                   if (event.point === startingPoint) break;
93604
93605                   while (true) {
93606                     var availableLEs = event.getAvailableLinkedEvents();
93607                     /* Did we hit a dead end? This shouldn't happen. Indicates some earlier
93608                      * part of the algorithm malfunctioned... please file a bug report. */
93609
93610                     if (availableLEs.length === 0) {
93611                       var firstPt = events[0].point;
93612                       var lastPt = events[events.length - 1].point;
93613                       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, "]."));
93614                     }
93615                     /* Only one way to go, so cotinue on the path */
93616
93617
93618                     if (availableLEs.length === 1) {
93619                       nextEvent = availableLEs[0].otherSE;
93620                       break;
93621                     }
93622                     /* We must have an intersection. Check for a completed loop */
93623
93624
93625                     var indexLE = null;
93626
93627                     for (var j = 0, jMax = intersectionLEs.length; j < jMax; j++) {
93628                       if (intersectionLEs[j].point === event.point) {
93629                         indexLE = j;
93630                         break;
93631                       }
93632                     }
93633                     /* Found a completed loop. Cut that off and make a ring */
93634
93635
93636                     if (indexLE !== null) {
93637                       var intersectionLE = intersectionLEs.splice(indexLE)[0];
93638                       var ringEvents = events.splice(intersectionLE.index);
93639                       ringEvents.unshift(ringEvents[0].otherSE);
93640                       ringsOut.push(new RingOut(ringEvents.reverse()));
93641                       continue;
93642                     }
93643                     /* register the intersection */
93644
93645
93646                     intersectionLEs.push({
93647                       index: events.length,
93648                       point: event.point
93649                     });
93650                     /* Choose the left-most option to continue the walk */
93651
93652                     var comparator = event.getLeftmostComparator(prevEvent);
93653                     nextEvent = availableLEs.sort(comparator)[0].otherSE;
93654                     break;
93655                   }
93656                 }
93657
93658                 ringsOut.push(new RingOut(events));
93659               }
93660
93661               return ringsOut;
93662             }
93663           }]);
93664
93665           function RingOut(events) {
93666             _classCallCheck$1(this, RingOut);
93667
93668             this.events = events;
93669
93670             for (var i = 0, iMax = events.length; i < iMax; i++) {
93671               events[i].segment.ringOut = this;
93672             }
93673
93674             this.poly = null;
93675           }
93676
93677           _createClass$1(RingOut, [{
93678             key: "getGeom",
93679             value: function getGeom() {
93680               // Remove superfluous points (ie extra points along a straight line),
93681               var prevPt = this.events[0].point;
93682               var points = [prevPt];
93683
93684               for (var i = 1, iMax = this.events.length - 1; i < iMax; i++) {
93685                 var _pt = this.events[i].point;
93686                 var _nextPt = this.events[i + 1].point;
93687                 if (compareVectorAngles(_pt, prevPt, _nextPt) === 0) continue;
93688                 points.push(_pt);
93689                 prevPt = _pt;
93690               } // ring was all (within rounding error of angle calc) colinear points
93691
93692
93693               if (points.length === 1) return null; // check if the starting point is necessary
93694
93695               var pt = points[0];
93696               var nextPt = points[1];
93697               if (compareVectorAngles(pt, prevPt, nextPt) === 0) points.shift();
93698               points.push(points[0]);
93699               var step = this.isExteriorRing() ? 1 : -1;
93700               var iStart = this.isExteriorRing() ? 0 : points.length - 1;
93701               var iEnd = this.isExteriorRing() ? points.length : -1;
93702               var orderedPoints = [];
93703
93704               for (var _i = iStart; _i != iEnd; _i += step) {
93705                 orderedPoints.push([points[_i].x, points[_i].y]);
93706               }
93707
93708               return orderedPoints;
93709             }
93710           }, {
93711             key: "isExteriorRing",
93712             value: function isExteriorRing() {
93713               if (this._isExteriorRing === undefined) {
93714                 var enclosing = this.enclosingRing();
93715                 this._isExteriorRing = enclosing ? !enclosing.isExteriorRing() : true;
93716               }
93717
93718               return this._isExteriorRing;
93719             }
93720           }, {
93721             key: "enclosingRing",
93722             value: function enclosingRing() {
93723               if (this._enclosingRing === undefined) {
93724                 this._enclosingRing = this._calcEnclosingRing();
93725               }
93726
93727               return this._enclosingRing;
93728             }
93729             /* Returns the ring that encloses this one, if any */
93730
93731           }, {
93732             key: "_calcEnclosingRing",
93733             value: function _calcEnclosingRing() {
93734               // start with the ealier sweep line event so that the prevSeg
93735               // chain doesn't lead us inside of a loop of ours
93736               var leftMostEvt = this.events[0];
93737
93738               for (var i = 1, iMax = this.events.length; i < iMax; i++) {
93739                 var evt = this.events[i];
93740                 if (SweepEvent$1.compare(leftMostEvt, evt) > 0) leftMostEvt = evt;
93741               }
93742
93743               var prevSeg = leftMostEvt.segment.prevInResult();
93744               var prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
93745
93746               while (true) {
93747                 // no segment found, thus no ring can enclose us
93748                 if (!prevSeg) return null; // no segments below prev segment found, thus the ring of the prev
93749                 // segment must loop back around and enclose us
93750
93751                 if (!prevPrevSeg) return prevSeg.ringOut; // if the two segments are of different rings, the ring of the prev
93752                 // segment must either loop around us or the ring of the prev prev
93753                 // seg, which would make us and the ring of the prev peers
93754
93755                 if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
93756                   if (prevPrevSeg.ringOut.enclosingRing() !== prevSeg.ringOut) {
93757                     return prevSeg.ringOut;
93758                   } else return prevSeg.ringOut.enclosingRing();
93759                 } // two segments are from the same ring, so this was a penisula
93760                 // of that ring. iterate downward, keep searching
93761
93762
93763                 prevSeg = prevPrevSeg.prevInResult();
93764                 prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
93765               }
93766             }
93767           }]);
93768
93769           return RingOut;
93770         }();
93771
93772         var PolyOut = /*#__PURE__*/function () {
93773           function PolyOut(exteriorRing) {
93774             _classCallCheck$1(this, PolyOut);
93775
93776             this.exteriorRing = exteriorRing;
93777             exteriorRing.poly = this;
93778             this.interiorRings = [];
93779           }
93780
93781           _createClass$1(PolyOut, [{
93782             key: "addInterior",
93783             value: function addInterior(ring) {
93784               this.interiorRings.push(ring);
93785               ring.poly = this;
93786             }
93787           }, {
93788             key: "getGeom",
93789             value: function getGeom() {
93790               var geom = [this.exteriorRing.getGeom()]; // exterior ring was all (within rounding error of angle calc) colinear points
93791
93792               if (geom[0] === null) return null;
93793
93794               for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
93795                 var ringGeom = this.interiorRings[i].getGeom(); // interior ring was all (within rounding error of angle calc) colinear points
93796
93797                 if (ringGeom === null) continue;
93798                 geom.push(ringGeom);
93799               }
93800
93801               return geom;
93802             }
93803           }]);
93804
93805           return PolyOut;
93806         }();
93807
93808         var MultiPolyOut = /*#__PURE__*/function () {
93809           function MultiPolyOut(rings) {
93810             _classCallCheck$1(this, MultiPolyOut);
93811
93812             this.rings = rings;
93813             this.polys = this._composePolys(rings);
93814           }
93815
93816           _createClass$1(MultiPolyOut, [{
93817             key: "getGeom",
93818             value: function getGeom() {
93819               var geom = [];
93820
93821               for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
93822                 var polyGeom = this.polys[i].getGeom(); // exterior ring was all (within rounding error of angle calc) colinear points
93823
93824                 if (polyGeom === null) continue;
93825                 geom.push(polyGeom);
93826               }
93827
93828               return geom;
93829             }
93830           }, {
93831             key: "_composePolys",
93832             value: function _composePolys(rings) {
93833               var polys = [];
93834
93835               for (var i = 0, iMax = rings.length; i < iMax; i++) {
93836                 var ring = rings[i];
93837                 if (ring.poly) continue;
93838                 if (ring.isExteriorRing()) polys.push(new PolyOut(ring));else {
93839                   var enclosingRing = ring.enclosingRing();
93840                   if (!enclosingRing.poly) polys.push(new PolyOut(enclosingRing));
93841                   enclosingRing.poly.addInterior(ring);
93842                 }
93843               }
93844
93845               return polys;
93846             }
93847           }]);
93848
93849           return MultiPolyOut;
93850         }();
93851         /**
93852          * NOTE:  We must be careful not to change any segments while
93853          *        they are in the SplayTree. AFAIK, there's no way to tell
93854          *        the tree to rebalance itself - thus before splitting
93855          *        a segment that's in the tree, we remove it from the tree,
93856          *        do the split, then re-insert it. (Even though splitting a
93857          *        segment *shouldn't* change its correct position in the
93858          *        sweep line tree, the reality is because of rounding errors,
93859          *        it sometimes does.)
93860          */
93861
93862
93863         var SweepLine = /*#__PURE__*/function () {
93864           function SweepLine(queue) {
93865             var comparator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Segment.compare;
93866
93867             _classCallCheck$1(this, SweepLine);
93868
93869             this.queue = queue;
93870             this.tree = new Tree(comparator);
93871             this.segments = [];
93872           }
93873
93874           _createClass$1(SweepLine, [{
93875             key: "process",
93876             value: function process(event) {
93877               var segment = event.segment;
93878               var newEvents = []; // if we've already been consumed by another segment,
93879               // clean up our body parts and get out
93880
93881               if (event.consumedBy) {
93882                 if (event.isLeft) this.queue.remove(event.otherSE);else this.tree.remove(segment);
93883                 return newEvents;
93884               }
93885
93886               var node = event.isLeft ? this.tree.insert(segment) : this.tree.find(segment);
93887               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.');
93888               var prevNode = node;
93889               var nextNode = node;
93890               var prevSeg = undefined;
93891               var nextSeg = undefined; // skip consumed segments still in tree
93892
93893               while (prevSeg === undefined) {
93894                 prevNode = this.tree.prev(prevNode);
93895                 if (prevNode === null) prevSeg = null;else if (prevNode.key.consumedBy === undefined) prevSeg = prevNode.key;
93896               } // skip consumed segments still in tree
93897
93898
93899               while (nextSeg === undefined) {
93900                 nextNode = this.tree.next(nextNode);
93901                 if (nextNode === null) nextSeg = null;else if (nextNode.key.consumedBy === undefined) nextSeg = nextNode.key;
93902               }
93903
93904               if (event.isLeft) {
93905                 // Check for intersections against the previous segment in the sweep line
93906                 var prevMySplitter = null;
93907
93908                 if (prevSeg) {
93909                   var prevInter = prevSeg.getIntersection(segment);
93910
93911                   if (prevInter !== null) {
93912                     if (!segment.isAnEndpoint(prevInter)) prevMySplitter = prevInter;
93913
93914                     if (!prevSeg.isAnEndpoint(prevInter)) {
93915                       var newEventsFromSplit = this._splitSafely(prevSeg, prevInter);
93916
93917                       for (var i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
93918                         newEvents.push(newEventsFromSplit[i]);
93919                       }
93920                     }
93921                   }
93922                 } // Check for intersections against the next segment in the sweep line
93923
93924
93925                 var nextMySplitter = null;
93926
93927                 if (nextSeg) {
93928                   var nextInter = nextSeg.getIntersection(segment);
93929
93930                   if (nextInter !== null) {
93931                     if (!segment.isAnEndpoint(nextInter)) nextMySplitter = nextInter;
93932
93933                     if (!nextSeg.isAnEndpoint(nextInter)) {
93934                       var _newEventsFromSplit = this._splitSafely(nextSeg, nextInter);
93935
93936                       for (var _i = 0, _iMax = _newEventsFromSplit.length; _i < _iMax; _i++) {
93937                         newEvents.push(_newEventsFromSplit[_i]);
93938                       }
93939                     }
93940                   }
93941                 } // For simplicity, even if we find more than one intersection we only
93942                 // spilt on the 'earliest' (sweep-line style) of the intersections.
93943                 // The other intersection will be handled in a future process().
93944
93945
93946                 if (prevMySplitter !== null || nextMySplitter !== null) {
93947                   var mySplitter = null;
93948                   if (prevMySplitter === null) mySplitter = nextMySplitter;else if (nextMySplitter === null) mySplitter = prevMySplitter;else {
93949                     var cmpSplitters = SweepEvent$1.comparePoints(prevMySplitter, nextMySplitter);
93950                     mySplitter = cmpSplitters <= 0 ? prevMySplitter : nextMySplitter;
93951                   } // Rounding errors can cause changes in ordering,
93952                   // so remove afected segments and right sweep events before splitting
93953
93954                   this.queue.remove(segment.rightSE);
93955                   newEvents.push(segment.rightSE);
93956
93957                   var _newEventsFromSplit2 = segment.split(mySplitter);
93958
93959                   for (var _i2 = 0, _iMax2 = _newEventsFromSplit2.length; _i2 < _iMax2; _i2++) {
93960                     newEvents.push(_newEventsFromSplit2[_i2]);
93961                   }
93962                 }
93963
93964                 if (newEvents.length > 0) {
93965                   // We found some intersections, so re-do the current event to
93966                   // make sure sweep line ordering is totally consistent for later
93967                   // use with the segment 'prev' pointers
93968                   this.tree.remove(segment);
93969                   newEvents.push(event);
93970                 } else {
93971                   // done with left event
93972                   this.segments.push(segment);
93973                   segment.prev = prevSeg;
93974                 }
93975               } else {
93976                 // event.isRight
93977                 // since we're about to be removed from the sweep line, check for
93978                 // intersections between our previous and next segments
93979                 if (prevSeg && nextSeg) {
93980                   var inter = prevSeg.getIntersection(nextSeg);
93981
93982                   if (inter !== null) {
93983                     if (!prevSeg.isAnEndpoint(inter)) {
93984                       var _newEventsFromSplit3 = this._splitSafely(prevSeg, inter);
93985
93986                       for (var _i3 = 0, _iMax3 = _newEventsFromSplit3.length; _i3 < _iMax3; _i3++) {
93987                         newEvents.push(_newEventsFromSplit3[_i3]);
93988                       }
93989                     }
93990
93991                     if (!nextSeg.isAnEndpoint(inter)) {
93992                       var _newEventsFromSplit4 = this._splitSafely(nextSeg, inter);
93993
93994                       for (var _i4 = 0, _iMax4 = _newEventsFromSplit4.length; _i4 < _iMax4; _i4++) {
93995                         newEvents.push(_newEventsFromSplit4[_i4]);
93996                       }
93997                     }
93998                   }
93999                 }
94000
94001                 this.tree.remove(segment);
94002               }
94003
94004               return newEvents;
94005             }
94006             /* Safely split a segment that is currently in the datastructures
94007              * IE - a segment other than the one that is currently being processed. */
94008
94009           }, {
94010             key: "_splitSafely",
94011             value: function _splitSafely(seg, pt) {
94012               // Rounding errors can cause changes in ordering,
94013               // so remove afected segments and right sweep events before splitting
94014               // removeNode() doesn't work, so have re-find the seg
94015               // https://github.com/w8r/splay-tree/pull/5
94016               this.tree.remove(seg);
94017               var rightSE = seg.rightSE;
94018               this.queue.remove(rightSE);
94019               var newEvents = seg.split(pt);
94020               newEvents.push(rightSE); // splitting can trigger consumption
94021
94022               if (seg.consumedBy === undefined) this.tree.insert(seg);
94023               return newEvents;
94024             }
94025           }]);
94026
94027           return SweepLine;
94028         }();
94029
94030         var POLYGON_CLIPPING_MAX_QUEUE_SIZE = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_QUEUE_SIZE || 1000000;
94031         var POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS || 1000000;
94032
94033         var Operation = /*#__PURE__*/function () {
94034           function Operation() {
94035             _classCallCheck$1(this, Operation);
94036           }
94037
94038           _createClass$1(Operation, [{
94039             key: "run",
94040             value: function run(type, geom, moreGeoms) {
94041               operation.type = type;
94042               rounder.reset();
94043               /* Convert inputs to MultiPoly objects */
94044
94045               var multipolys = [new MultiPolyIn(geom, true)];
94046
94047               for (var i = 0, iMax = moreGeoms.length; i < iMax; i++) {
94048                 multipolys.push(new MultiPolyIn(moreGeoms[i], false));
94049               }
94050
94051               operation.numMultiPolys = multipolys.length;
94052               /* BBox optimization for difference operation
94053                * If the bbox of a multipolygon that's part of the clipping doesn't
94054                * intersect the bbox of the subject at all, we can just drop that
94055                * multiploygon. */
94056
94057               if (operation.type === 'difference') {
94058                 // in place removal
94059                 var subject = multipolys[0];
94060                 var _i = 1;
94061
94062                 while (_i < multipolys.length) {
94063                   if (getBboxOverlap(multipolys[_i].bbox, subject.bbox) !== null) _i++;else multipolys.splice(_i, 1);
94064                 }
94065               }
94066               /* BBox optimization for intersection operation
94067                * If we can find any pair of multipolygons whose bbox does not overlap,
94068                * then the result will be empty. */
94069
94070
94071               if (operation.type === 'intersection') {
94072                 // TODO: this is O(n^2) in number of polygons. By sorting the bboxes,
94073                 //       it could be optimized to O(n * ln(n))
94074                 for (var _i2 = 0, _iMax = multipolys.length; _i2 < _iMax; _i2++) {
94075                   var mpA = multipolys[_i2];
94076
94077                   for (var j = _i2 + 1, jMax = multipolys.length; j < jMax; j++) {
94078                     if (getBboxOverlap(mpA.bbox, multipolys[j].bbox) === null) return [];
94079                   }
94080                 }
94081               }
94082               /* Put segment endpoints in a priority queue */
94083
94084
94085               var queue = new Tree(SweepEvent$1.compare);
94086
94087               for (var _i3 = 0, _iMax2 = multipolys.length; _i3 < _iMax2; _i3++) {
94088                 var sweepEvents = multipolys[_i3].getSweepEvents();
94089
94090                 for (var _j = 0, _jMax = sweepEvents.length; _j < _jMax; _j++) {
94091                   queue.insert(sweepEvents[_j]);
94092
94093                   if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
94094                     // prevents an infinite loop, an otherwise common manifestation of bugs
94095                     throw new Error('Infinite loop when putting segment endpoints in a priority queue ' + '(queue size too big). Please file a bug report.');
94096                   }
94097                 }
94098               }
94099               /* Pass the sweep line over those endpoints */
94100
94101
94102               var sweepLine = new SweepLine(queue);
94103               var prevQueueSize = queue.size;
94104               var node = queue.pop();
94105
94106               while (node) {
94107                 var evt = node.key;
94108
94109                 if (queue.size === prevQueueSize) {
94110                   // prevents an infinite loop, an otherwise common manifestation of bugs
94111                   var seg = evt.segment;
94112                   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.');
94113                 }
94114
94115                 if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
94116                   // prevents an infinite loop, an otherwise common manifestation of bugs
94117                   throw new Error('Infinite loop when passing sweep line over endpoints ' + '(queue size too big). Please file a bug report.');
94118                 }
94119
94120                 if (sweepLine.segments.length > POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS) {
94121                   // prevents an infinite loop, an otherwise common manifestation of bugs
94122                   throw new Error('Infinite loop when passing sweep line over endpoints ' + '(too many sweep line segments). Please file a bug report.');
94123                 }
94124
94125                 var newEvents = sweepLine.process(evt);
94126
94127                 for (var _i4 = 0, _iMax3 = newEvents.length; _i4 < _iMax3; _i4++) {
94128                   var _evt = newEvents[_i4];
94129                   if (_evt.consumedBy === undefined) queue.insert(_evt);
94130                 }
94131
94132                 prevQueueSize = queue.size;
94133                 node = queue.pop();
94134               } // free some memory we don't need anymore
94135
94136
94137               rounder.reset();
94138               /* Collect and compile segments we're keeping into a multipolygon */
94139
94140               var ringsOut = RingOut.factory(sweepLine.segments);
94141               var result = new MultiPolyOut(ringsOut);
94142               return result.getGeom();
94143             }
94144           }]);
94145
94146           return Operation;
94147         }(); // singleton available by import
94148
94149
94150         var operation = new Operation();
94151
94152         var union$1 = function union(geom) {
94153           for (var _len = arguments.length, moreGeoms = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
94154             moreGeoms[_key - 1] = arguments[_key];
94155           }
94156
94157           return operation.run('union', geom, moreGeoms);
94158         };
94159
94160         var intersection$1$1 = function intersection(geom) {
94161           for (var _len2 = arguments.length, moreGeoms = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
94162             moreGeoms[_key2 - 1] = arguments[_key2];
94163           }
94164
94165           return operation.run('intersection', geom, moreGeoms);
94166         };
94167
94168         var xor = function xor(geom) {
94169           for (var _len3 = arguments.length, moreGeoms = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
94170             moreGeoms[_key3 - 1] = arguments[_key3];
94171           }
94172
94173           return operation.run('xor', geom, moreGeoms);
94174         };
94175
94176         var difference = function difference(subjectGeom) {
94177           for (var _len4 = arguments.length, clippingGeoms = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
94178             clippingGeoms[_key4 - 1] = arguments[_key4];
94179           }
94180
94181           return operation.run('difference', subjectGeom, clippingGeoms);
94182         };
94183
94184         var index$1 = {
94185           union: union$1,
94186           intersection: intersection$1$1,
94187           xor: xor,
94188           difference: difference
94189         };
94190
94191         var geojsonPrecision = createCommonjsModule(function (module) {
94192           (function () {
94193             function parse(t, coordinatePrecision, extrasPrecision) {
94194               function point(p) {
94195                 return p.map(function (e, index) {
94196                   if (index < 2) {
94197                     return 1 * e.toFixed(coordinatePrecision);
94198                   } else {
94199                     return 1 * e.toFixed(extrasPrecision);
94200                   }
94201                 });
94202               }
94203
94204               function multi(l) {
94205                 return l.map(point);
94206               }
94207
94208               function poly(p) {
94209                 return p.map(multi);
94210               }
94211
94212               function multiPoly(m) {
94213                 return m.map(poly);
94214               }
94215
94216               function geometry(obj) {
94217                 if (!obj) {
94218                   return {};
94219                 }
94220
94221                 switch (obj.type) {
94222                   case "Point":
94223                     obj.coordinates = point(obj.coordinates);
94224                     return obj;
94225
94226                   case "LineString":
94227                   case "MultiPoint":
94228                     obj.coordinates = multi(obj.coordinates);
94229                     return obj;
94230
94231                   case "Polygon":
94232                   case "MultiLineString":
94233                     obj.coordinates = poly(obj.coordinates);
94234                     return obj;
94235
94236                   case "MultiPolygon":
94237                     obj.coordinates = multiPoly(obj.coordinates);
94238                     return obj;
94239
94240                   case "GeometryCollection":
94241                     obj.geometries = obj.geometries.map(geometry);
94242                     return obj;
94243
94244                   default:
94245                     return {};
94246                 }
94247               }
94248
94249               function feature(obj) {
94250                 obj.geometry = geometry(obj.geometry);
94251                 return obj;
94252               }
94253
94254               function featureCollection(f) {
94255                 f.features = f.features.map(feature);
94256                 return f;
94257               }
94258
94259               function geometryCollection(g) {
94260                 g.geometries = g.geometries.map(geometry);
94261                 return g;
94262               }
94263
94264               if (!t) {
94265                 return t;
94266               }
94267
94268               switch (t.type) {
94269                 case "Feature":
94270                   return feature(t);
94271
94272                 case "GeometryCollection":
94273                   return geometryCollection(t);
94274
94275                 case "FeatureCollection":
94276                   return featureCollection(t);
94277
94278                 case "Point":
94279                 case "LineString":
94280                 case "Polygon":
94281                 case "MultiPoint":
94282                 case "MultiPolygon":
94283                 case "MultiLineString":
94284                   return geometry(t);
94285
94286                 default:
94287                   return t;
94288               }
94289             }
94290
94291             module.exports = parse;
94292             module.exports.parse = parse;
94293           })();
94294         });
94295
94296         function isObject$4(obj) {
94297           return _typeof(obj) === 'object' && obj !== null;
94298         }
94299
94300         function forEach(obj, cb) {
94301           if (Array.isArray(obj)) {
94302             obj.forEach(cb);
94303           } else if (isObject$4(obj)) {
94304             Object.keys(obj).forEach(function (key) {
94305               var val = obj[key];
94306               cb(val, key);
94307             });
94308           }
94309         }
94310
94311         function getTreeDepth(obj) {
94312           var depth = 0;
94313
94314           if (Array.isArray(obj) || isObject$4(obj)) {
94315             forEach(obj, function (val) {
94316               if (Array.isArray(val) || isObject$4(val)) {
94317                 var tmpDepth = getTreeDepth(val);
94318
94319                 if (tmpDepth > depth) {
94320                   depth = tmpDepth;
94321                 }
94322               }
94323             });
94324             return depth + 1;
94325           }
94326
94327           return depth;
94328         }
94329
94330         function stringify(obj, options) {
94331           options = options || {};
94332           var indent = JSON.stringify([1], null, get$5(options, 'indent', 2)).slice(2, -3);
94333           var addMargin = get$5(options, 'margins', false);
94334           var addArrayMargin = get$5(options, 'arrayMargins', false);
94335           var addObjectMargin = get$5(options, 'objectMargins', false);
94336           var maxLength = indent === '' ? Infinity : get$5(options, 'maxLength', 80);
94337           var maxNesting = get$5(options, 'maxNesting', Infinity);
94338           return function _stringify(obj, currentIndent, reserved) {
94339             if (obj && typeof obj.toJSON === 'function') {
94340               obj = obj.toJSON();
94341             }
94342
94343             var string = JSON.stringify(obj);
94344
94345             if (string === undefined) {
94346               return string;
94347             }
94348
94349             var length = maxLength - currentIndent.length - reserved;
94350             var treeDepth = getTreeDepth(obj);
94351
94352             if (treeDepth <= maxNesting && string.length <= length) {
94353               var prettified = prettify(string, {
94354                 addMargin: addMargin,
94355                 addArrayMargin: addArrayMargin,
94356                 addObjectMargin: addObjectMargin
94357               });
94358
94359               if (prettified.length <= length) {
94360                 return prettified;
94361               }
94362             }
94363
94364             if (isObject$4(obj)) {
94365               var nextIndent = currentIndent + indent;
94366               var items = [];
94367               var delimiters;
94368
94369               var comma = function comma(array, index) {
94370                 return index === array.length - 1 ? 0 : 1;
94371               };
94372
94373               if (Array.isArray(obj)) {
94374                 for (var index = 0; index < obj.length; index++) {
94375                   items.push(_stringify(obj[index], nextIndent, comma(obj, index)) || 'null');
94376                 }
94377
94378                 delimiters = '[]';
94379               } else {
94380                 Object.keys(obj).forEach(function (key, index, array) {
94381                   var keyPart = JSON.stringify(key) + ': ';
94382
94383                   var value = _stringify(obj[key], nextIndent, keyPart.length + comma(array, index));
94384
94385                   if (value !== undefined) {
94386                     items.push(keyPart + value);
94387                   }
94388                 });
94389                 delimiters = '{}';
94390               }
94391
94392               if (items.length > 0) {
94393                 return [delimiters[0], indent + items.join(',\n' + nextIndent), delimiters[1]].join('\n' + currentIndent);
94394               }
94395             }
94396
94397             return string;
94398           }(obj, '', 0);
94399         } // Note: This regex matches even invalid JSON strings, but since we’re
94400         // working on the output of `JSON.stringify` we know that only valid strings
94401         // are present (unless the user supplied a weird `options.indent` but in
94402         // that case we don’t care since the output would be invalid anyway).
94403
94404
94405         var stringOrChar = /("(?:[^\\"]|\\.)*")|[:,\][}{]/g;
94406
94407         function prettify(string, options) {
94408           options = options || {};
94409           var tokens = {
94410             '{': '{',
94411             '}': '}',
94412             '[': '[',
94413             ']': ']',
94414             ',': ', ',
94415             ':': ': '
94416           };
94417
94418           if (options.addMargin || options.addObjectMargin) {
94419             tokens['{'] = '{ ';
94420             tokens['}'] = ' }';
94421           }
94422
94423           if (options.addMargin || options.addArrayMargin) {
94424             tokens['['] = '[ ';
94425             tokens[']'] = ' ]';
94426           }
94427
94428           return string.replace(stringOrChar, function (match, string) {
94429             return string ? match : tokens[match];
94430           });
94431         }
94432
94433         function get$5(options, name, defaultValue) {
94434           return name in options ? options[name] : defaultValue;
94435         }
94436
94437         var jsonStringifyPrettyCompact = stringify;
94438
94439         var _default$3 = /*#__PURE__*/function () {
94440           // constructor
94441           //
94442           // `fc`  Optional FeatureCollection of known features
94443           //
94444           // Optionally pass a GeoJSON FeatureCollection of known features which we can refer to later.
94445           // Each feature must have a filename-like `id`, for example: `something.geojson`
94446           //
94447           // {
94448           //   "type": "FeatureCollection"
94449           //   "features": [
94450           //     {
94451           //       "type": "Feature",
94452           //       "id": "philly_metro.geojson",
94453           //       "properties": { … },
94454           //       "geometry": { … }
94455           //     }
94456           //   ]
94457           // }
94458           function _default(fc) {
94459             var _this = this;
94460
94461             _classCallCheck(this, _default);
94462
94463             // The _cache retains resolved features, so if you ask for the same thing multiple times
94464             // we don't repeat the expensive resolving/clipping operations.
94465             //
94466             // Each feature has a stable identifier that is used as the cache key.
94467             // The identifiers look like:
94468             // - for point locations, the stringified point:          e.g. '[8.67039,49.41882]'
94469             // - for geojson locations, the geojson id:               e.g. 'de-hamburg.geojson'
94470             // - for countrycoder locations, feature.id property:     e.g. 'Q2'  (countrycoder uses Wikidata identifiers)
94471             // - for aggregated locationSets, +[include]-[exclude]:   e.g '+[Q2]-[Q18,Q27611]'
94472             this._cache = {}; // When strict mode = true, throw on invalid locations or locationSets.
94473             // When strict mode = false, return `null` for invalid locations or locationSets.
94474
94475             this._strict = true; // process input FeatureCollection
94476
94477             if (fc && fc.type === 'FeatureCollection' && Array.isArray(fc.features)) {
94478               fc.features.forEach(function (feature) {
94479                 feature.properties = feature.properties || {};
94480                 var props = feature.properties; // get `id` from either `id` or `properties`
94481
94482                 var id = feature.id || props.id;
94483                 if (!id || !/^\S+\.geojson$/i.test(id)) return; // ensure `id` exists and is lowercase
94484
94485                 id = id.toLowerCase();
94486                 feature.id = id;
94487                 props.id = id; // ensure `area` property exists
94488
94489                 if (!props.area) {
94490                   var area = geojsonArea.geometry(feature.geometry) / 1e6; // m² to km²
94491
94492                   props.area = Number(area.toFixed(2));
94493                 }
94494
94495                 _this._cache[id] = feature;
94496               });
94497             } // Replace CountryCoder world geometry to be a polygon covering the world.
94498
94499
94500             var world = _cloneDeep(feature('Q2'));
94501
94502             world.geometry = {
94503               type: 'Polygon',
94504               coordinates: [[[-180, -90], [180, -90], [180, 90], [-180, 90], [-180, -90]]]
94505             };
94506             world.id = 'Q2';
94507             world.properties.id = 'Q2';
94508             world.properties.area = geojsonArea.geometry(world.geometry) / 1e6; // m² to km²
94509
94510             this._cache.Q2 = world;
94511           } // validateLocation
94512           // `location`  The location to validate
94513           //
94514           // Pass a `location` value to validate
94515           //
94516           // Returns a result like:
94517           //   {
94518           //     type:     'point', 'geojson', or 'countrycoder'
94519           //     location:  the queried location
94520           //     id:        the stable identifier for the feature
94521           //   }
94522           // or `null` if the location is invalid
94523           //
94524
94525
94526           _createClass(_default, [{
94527             key: "validateLocation",
94528             value: function validateLocation(location) {
94529               if (Array.isArray(location)) {
94530                 // a [lon,lat] coordinate pair?
94531                 if (location.length === 2 && Number.isFinite(location[0]) && Number.isFinite(location[1]) && location[0] >= -180 && location[0] <= 180 && location[1] >= -90 && location[1] <= 90) {
94532                   var id = '[' + location.toString() + ']';
94533                   return {
94534                     type: 'point',
94535                     location: location,
94536                     id: id
94537                   };
94538                 }
94539               } else if (typeof location === 'string' && /^\S+\.geojson$/i.test(location)) {
94540                 // a .geojson filename?
94541                 var _id = location.toLowerCase();
94542
94543                 if (this._cache[_id]) {
94544                   return {
94545                     type: 'geojson',
94546                     location: location,
94547                     id: _id
94548                   };
94549                 }
94550               } else if (typeof location === 'string' || typeof location === 'number') {
94551                 // a country-coder value?
94552                 var feature$1 = feature(location);
94553
94554                 if (feature$1) {
94555                   // Use wikidata QID as the identifier, since that seems to be the one
94556                   // property that everything in CountryCoder is guaranteed to have.
94557                   var _id2 = feature$1.properties.wikidata;
94558                   return {
94559                     type: 'countrycoder',
94560                     location: location,
94561                     id: _id2
94562                   };
94563                 }
94564               }
94565
94566               if (this._strict) {
94567                 throw new Error("validateLocation:  Invalid location: \"".concat(location, "\"."));
94568               } else {
94569                 return null;
94570               }
94571             } // resolveLocation
94572             // `location`  The location to resolve
94573             //
94574             // Pass a `location` value to resolve
94575             //
94576             // Returns a result like:
94577             //   {
94578             //     type:      'point', 'geojson', or 'countrycoder'
94579             //     location:  the queried location
94580             //     id:        a stable identifier for the feature
94581             //     feature:   the resolved GeoJSON feature
94582             //   }
94583             //  or `null` if the location is invalid
94584             //
94585
94586           }, {
94587             key: "resolveLocation",
94588             value: function resolveLocation(location) {
94589               var valid = this.validateLocation(location);
94590               if (!valid) return null;
94591               var id = valid.id; // return a result from cache if we can
94592
94593               if (this._cache[id]) {
94594                 return Object.assign(valid, {
94595                   feature: this._cache[id]
94596                 });
94597               } // a [lon,lat] coordinate pair?
94598
94599
94600               if (valid.type === 'point') {
94601                 var RADIUS = 25000; // meters
94602
94603                 var EDGES = 10;
94604                 var PRECISION = 3;
94605                 var area = Math.PI * RADIUS * RADIUS / 1e6; // m² to km²
94606
94607                 var feature$1 = this._cache[id] = geojsonPrecision({
94608                   type: 'Feature',
94609                   id: id,
94610                   properties: {
94611                     id: id,
94612                     area: Number(area.toFixed(2))
94613                   },
94614                   geometry: circleToPolygon(location, RADIUS, EDGES)
94615                 }, PRECISION);
94616                 return Object.assign(valid, {
94617                   feature: feature$1
94618                 }); // a .geojson filename?
94619               } else if (valid.type === 'geojson') ; else if (valid.type === 'countrycoder') {
94620                 var _feature = _cloneDeep(feature(id));
94621
94622                 var props = _feature.properties; // -> This block of code is weird and requires some explanation. <-
94623                 // CountryCoder includes higher level features which are made up of members.
94624                 // These features don't have their own geometry, but CountryCoder provides an
94625                 //   `aggregateFeature` method to combine these members into a MultiPolygon.
94626                 // BUT, when we try to actually work with these aggregated MultiPolygons,
94627                 //   Turf/JSTS gets crashy because of topography bugs.
94628                 // SO, we'll aggregate the features ourselves by unioning them together.
94629                 // This approach also has the benefit of removing all the internal boaders and
94630                 //   simplifying the regional polygons a lot.
94631
94632                 if (Array.isArray(props.members)) {
94633                   var seed = _feature.geometry ? _feature : null;
94634                   var aggregate = props.members.reduce(_locationReducer.bind(this), seed);
94635                   _feature.geometry = aggregate.geometry;
94636                 } // ensure `area` property exists
94637
94638
94639                 if (!props.area) {
94640                   var _area = geojsonArea.geometry(_feature.geometry) / 1e6; // m² to km²
94641
94642
94643                   props.area = Number(_area.toFixed(2));
94644                 } // ensure `id` property exists
94645
94646
94647                 _feature.id = id;
94648                 props.id = id;
94649                 this._cache[id] = _feature;
94650                 return Object.assign(valid, {
94651                   feature: _feature
94652                 });
94653               }
94654
94655               if (this._strict) {
94656                 throw new Error("resolveLocation:  Couldn't resolve location \"".concat(location, "\"."));
94657               } else {
94658                 return null;
94659               }
94660             } // validateLocationSet
94661             // `locationSet`  the locationSet to validate
94662             //
94663             // Pass a locationSet Object to validate like:
94664             //   {
94665             //     include: [ Array of locations ],
94666             //     exclude: [ Array of locations ]
94667             //   }
94668             //
94669             // Returns a result like:
94670             //   {
94671             //     type:         'locationset'
94672             //     locationSet:  the queried locationSet
94673             //     id:           the stable identifier for the feature
94674             //   }
94675             // or `null` if the locationSet is invalid
94676             //
94677
94678           }, {
94679             key: "validateLocationSet",
94680             value: function validateLocationSet(locationSet) {
94681               locationSet = locationSet || {};
94682               var validator = this.validateLocation.bind(this);
94683               var include = (locationSet.include || []).map(validator).filter(Boolean);
94684               var exclude = (locationSet.exclude || []).map(validator).filter(Boolean);
94685
94686               if (!include.length) {
94687                 if (this._strict) {
94688                   throw new Error("validateLocationSet:  LocationSet includes nothing.");
94689                 } else {
94690                   // non-strict mode, replace an empty locationSet with one that includes "the world"
94691                   locationSet.include = ['Q2'];
94692                   include = [{
94693                     type: 'countrycoder',
94694                     location: 'Q2',
94695                     id: 'Q2'
94696                   }];
94697                 }
94698               } // generate stable identifier
94699
94700
94701               include.sort(_sortLocations);
94702               var id = '+[' + include.map(function (d) {
94703                 return d.id;
94704               }).join(',') + ']';
94705
94706               if (exclude.length) {
94707                 exclude.sort(_sortLocations);
94708                 id += '-[' + exclude.map(function (d) {
94709                   return d.id;
94710                 }).join(',') + ']';
94711               }
94712
94713               return {
94714                 type: 'locationset',
94715                 locationSet: locationSet,
94716                 id: id
94717               };
94718             } // resolveLocationSet
94719             // `locationSet`  the locationSet to resolve
94720             //
94721             // Pass a locationSet Object to validate like:
94722             //   {
94723             //     include: [ Array of locations ],
94724             //     exclude: [ Array of locations ]
94725             //   }
94726             //
94727             // Returns a result like:
94728             //   {
94729             //     type:         'locationset'
94730             //     locationSet:  the queried locationSet
94731             //     id:           the stable identifier for the feature
94732             //     feature:      the resolved GeoJSON feature
94733             //   }
94734             // or `null` if the locationSet is invalid
94735             //
94736
94737           }, {
94738             key: "resolveLocationSet",
94739             value: function resolveLocationSet(locationSet) {
94740               locationSet = locationSet || {};
94741               var valid = this.validateLocationSet(locationSet);
94742               if (!valid) return null;
94743               var id = valid.id; // return a result from cache if we can
94744
94745               if (this._cache[id]) {
94746                 return Object.assign(valid, {
94747                   feature: this._cache[id]
94748                 });
94749               }
94750
94751               var resolver = this.resolveLocation.bind(this);
94752               var include = (locationSet.include || []).map(resolver).filter(Boolean);
94753               var exclude = (locationSet.exclude || []).map(resolver).filter(Boolean); // return quickly if it's a single included location..
94754
94755               if (include.length === 1 && exclude.length === 0) {
94756                 return Object.assign(valid, {
94757                   feature: include[0].feature
94758                 });
94759               } // calculate unions
94760
94761
94762               var includeGeoJSON = include.map(function (d) {
94763                 return d.location;
94764               }).reduce(_locationReducer.bind(this), null);
94765               var excludeGeoJSON = exclude.map(function (d) {
94766                 return d.location;
94767               }).reduce(_locationReducer.bind(this), null); // calculate difference, update `area` and return result
94768
94769               var resultGeoJSON = excludeGeoJSON ? _clip(includeGeoJSON, excludeGeoJSON, 'DIFFERENCE') : includeGeoJSON;
94770               var area = geojsonArea.geometry(resultGeoJSON.geometry) / 1e6; // m² to km²
94771
94772               resultGeoJSON.id = id;
94773               resultGeoJSON.properties = {
94774                 id: id,
94775                 area: Number(area.toFixed(2))
94776               };
94777               this._cache[id] = resultGeoJSON;
94778               return Object.assign(valid, {
94779                 feature: resultGeoJSON
94780               });
94781             } // strict
94782             //
94783
94784           }, {
94785             key: "strict",
94786             value: function strict(val) {
94787               if (val === undefined) {
94788                 // get
94789                 return this._strict;
94790               } else {
94791                 // set
94792                 this._strict = val;
94793                 return this;
94794               }
94795             } // cache
94796             // convenience method to access the internal cache
94797
94798           }, {
94799             key: "cache",
94800             value: function cache() {
94801               return this._cache;
94802             } // stringify
94803             // convenience method to prettyStringify the given object
94804
94805           }, {
94806             key: "stringify",
94807             value: function stringify(obj, options) {
94808               return jsonStringifyPrettyCompact(obj, options);
94809             }
94810           }]);
94811
94812           return _default;
94813         }(); // Wrap the mfogel/polygon-clipping library and return a GeoJSON feature.
94814
94815         function _clip(a, b, which) {
94816           var fn = {
94817             UNION: index$1.union,
94818             DIFFERENCE: index$1.difference
94819           }[which];
94820           var coords = fn(a.geometry.coordinates, b.geometry.coordinates);
94821           return {
94822             type: 'Feature',
94823             properties: {},
94824             geometry: {
94825               type: whichType(coords),
94826               coordinates: coords
94827             }
94828           }; // is this a Polygon or a MultiPolygon?
94829
94830           function whichType(coords) {
94831             var a = Array.isArray(coords);
94832             var b = a && Array.isArray(coords[0]);
94833             var c = b && Array.isArray(coords[0][0]);
94834             var d = c && Array.isArray(coords[0][0][0]);
94835             return d ? 'MultiPolygon' : 'Polygon';
94836           }
94837         } // Reduce an array of locations into a single GeoJSON feature
94838
94839
94840         function _locationReducer(accumulator, location) {
94841           /* eslint-disable no-console, no-invalid-this */
94842           var result;
94843
94844           try {
94845             var resolved = this.resolveLocation(location);
94846
94847             if (!resolved || !resolved.feature) {
94848               console.warn("Warning:  Couldn't resolve location \"".concat(location, "\""));
94849               return accumulator;
94850             }
94851
94852             result = !accumulator ? resolved.feature : _clip(accumulator, resolved.feature, 'UNION');
94853           } catch (e) {
94854             console.warn("Warning:  Error resolving location \"".concat(location, "\""));
94855             console.warn(e);
94856             result = accumulator;
94857           }
94858
94859           return result;
94860           /* eslint-enable no-console, no-invalid-this */
94861         }
94862
94863         function _cloneDeep(obj) {
94864           return JSON.parse(JSON.stringify(obj));
94865         } // Sorting the location lists is ok because they end up unioned together.
94866         // This sorting makes it possible to generate a deterministic id.
94867
94868
94869         function _sortLocations(a, b) {
94870           var rank = {
94871             countrycoder: 1,
94872             geojson: 2,
94873             point: 3
94874           };
94875           var aRank = rank[a.type];
94876           var bRank = rank[b.type];
94877           return aRank > bRank ? 1 : aRank < bRank ? -1 : a.id.localeCompare(b.id);
94878         }
94879
94880         var _oci = null;
94881         function uiSuccess(context) {
94882           var MAXEVENTS = 2;
94883           var dispatch$1 = dispatch('cancel');
94884
94885           var _changeset;
94886
94887           var _location;
94888
94889           ensureOSMCommunityIndex(); // start fetching the data
94890
94891           function ensureOSMCommunityIndex() {
94892             var data = _mainFileFetcher;
94893             return Promise.all([data.get('oci_resources'), data.get('oci_features')]).then(function (vals) {
94894               if (_oci) return _oci;
94895               var ociResources = vals[0].resources;
94896               var loco = new _default$3(vals[1]);
94897               var ociFeatures = {};
94898               Object.values(ociResources).forEach(function (resource) {
94899                 var feature = loco.resolveLocationSet(resource.locationSet).feature;
94900                 var ociFeature = ociFeatures[feature.id];
94901
94902                 if (!ociFeature) {
94903                   ociFeature = JSON.parse(JSON.stringify(feature)); // deep clone
94904
94905                   ociFeature.properties.resourceIDs = new Set();
94906                   ociFeatures[feature.id] = ociFeature;
94907                 }
94908
94909                 ociFeature.properties.resourceIDs.add(resource.id);
94910               });
94911               return _oci = {
94912                 features: ociFeatures,
94913                 resources: ociResources,
94914                 query: whichPolygon_1({
94915                   type: 'FeatureCollection',
94916                   features: Object.values(ociFeatures)
94917                 })
94918               };
94919             });
94920           } // string-to-date parsing in JavaScript is weird
94921
94922
94923           function parseEventDate(when) {
94924             if (!when) return;
94925             var raw = when.trim();
94926             if (!raw) return;
94927
94928             if (!/Z$/.test(raw)) {
94929               // if no trailing 'Z', add one
94930               raw += 'Z'; // this forces date to be parsed as a UTC date
94931             }
94932
94933             var parsed = new Date(raw);
94934             return new Date(parsed.toUTCString().substr(0, 25)); // convert to local timezone
94935           }
94936
94937           function success(selection) {
94938             var header = selection.append('div').attr('class', 'header fillL');
94939             header.append('h3').html(_t.html('success.just_edited'));
94940             header.append('button').attr('class', 'close').on('click', function () {
94941               return dispatch$1.call('cancel');
94942             }).call(svgIcon('#iD-icon-close'));
94943             var body = selection.append('div').attr('class', 'body save-success fillL');
94944             var summary = body.append('div').attr('class', 'save-summary');
94945             summary.append('h3').html(_t.html('success.thank_you' + (_location ? '_location' : ''), {
94946               where: _location
94947             }));
94948             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'));
94949             var osm = context.connection();
94950             if (!osm) return;
94951             var changesetURL = osm.changesetURL(_changeset.id);
94952             var table = summary.append('table').attr('class', 'summary-table');
94953             var row = table.append('tr').attr('class', 'summary-row');
94954             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');
94955             var summaryDetail = row.append('td').attr('class', 'cell-detail summary-detail');
94956             summaryDetail.append('a').attr('class', 'cell-detail summary-view-on-osm').attr('target', '_blank').attr('href', changesetURL).html(_t.html('success.view_on_osm'));
94957             summaryDetail.append('div').html(_t.html('success.changeset_id', {
94958               changeset_id: "<a href=\"".concat(changesetURL, "\" target=\"_blank\">").concat(_changeset.id, "</a>")
94959             })); // Get OSM community index features intersecting the map..
94960
94961             ensureOSMCommunityIndex().then(function (oci) {
94962               var communities = [];
94963               var properties = oci.query(context.map().center(), true) || []; // Gather the communities from the result
94964
94965               properties.forEach(function (props) {
94966                 var resourceIDs = Array.from(props.resourceIDs);
94967                 resourceIDs.forEach(function (resourceID) {
94968                   var resource = oci.resources[resourceID];
94969                   communities.push({
94970                     area: props.area || Infinity,
94971                     order: resource.order || 0,
94972                     resource: resource
94973                   });
94974                 });
94975               }); // sort communities by feature area ascending, community order descending
94976
94977               communities.sort(function (a, b) {
94978                 return a.area - b.area || b.order - a.order;
94979               });
94980               body.call(showCommunityLinks, communities.map(function (c) {
94981                 return c.resource;
94982               }));
94983             });
94984           }
94985
94986           function showCommunityLinks(selection, resources) {
94987             var communityLinks = selection.append('div').attr('class', 'save-communityLinks');
94988             communityLinks.append('h3').html(_t.html('success.like_osm'));
94989             var table = communityLinks.append('table').attr('class', 'community-table');
94990             var row = table.selectAll('.community-row').data(resources);
94991             var rowEnter = row.enter().append('tr').attr('class', 'community-row');
94992             rowEnter.append('td').attr('class', 'cell-icon community-icon').append('a').attr('target', '_blank').attr('href', function (d) {
94993               return d.url;
94994             }).append('svg').attr('class', 'logo-small').append('use').attr('xlink:href', function (d) {
94995               return "#community-".concat(d.type);
94996             });
94997             var communityDetail = rowEnter.append('td').attr('class', 'cell-detail community-detail');
94998             communityDetail.each(showCommunityDetails);
94999             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'));
95000           }
95001
95002           function showCommunityDetails(d) {
95003             var selection = select(this);
95004             var communityID = d.id;
95005             var replacements = {
95006               url: linkify(d.url),
95007               signupUrl: linkify(d.signupUrl || d.url)
95008             };
95009             selection.append('div').attr('class', 'community-name').append('a').attr('target', '_blank').attr('href', d.url).html(_t.html("community.".concat(d.id, ".name")));
95010             var descriptionHTML = _t.html("community.".concat(d.id, ".description"), replacements);
95011
95012             if (d.type === 'reddit') {
95013               // linkify subreddits  #4997
95014               descriptionHTML = descriptionHTML.replace(/(\/r\/\w*\/*)/i, function (match) {
95015                 return linkify(d.url, match);
95016               });
95017             }
95018
95019             selection.append('div').attr('class', 'community-description').html(descriptionHTML);
95020
95021             if (d.extendedDescription || d.languageCodes && d.languageCodes.length) {
95022               selection.append('div').call(uiDisclosure(context, "community-more-".concat(d.id), false).expanded(false).updatePreference(false).label(_t.html('success.more')).content(showMore));
95023             }
95024
95025             var nextEvents = (d.events || []).map(function (event) {
95026               event.date = parseEventDate(event.when);
95027               return event;
95028             }).filter(function (event) {
95029               // date is valid and future (or today)
95030               var t = event.date.getTime();
95031               var now = new Date().setHours(0, 0, 0, 0);
95032               return !isNaN(t) && t >= now;
95033             }).sort(function (a, b) {
95034               // sort by date ascending
95035               return a.date < b.date ? -1 : a.date > b.date ? 1 : 0;
95036             }).slice(0, MAXEVENTS); // limit number of events shown
95037
95038             if (nextEvents.length) {
95039               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);
95040             }
95041
95042             function showMore(selection) {
95043               var more = selection.selectAll('.community-more').data([0]);
95044               var moreEnter = more.enter().append('div').attr('class', 'community-more');
95045
95046               if (d.extendedDescription) {
95047                 moreEnter.append('div').attr('class', 'community-extended-description').html(_t.html("community.".concat(d.id, ".extendedDescription"), replacements));
95048               }
95049
95050               if (d.languageCodes && d.languageCodes.length) {
95051                 var languageList = d.languageCodes.map(function (code) {
95052                   return _mainLocalizer.languageName(code);
95053                 }).join(', ');
95054                 moreEnter.append('div').attr('class', 'community-languages').html(_t.html('success.languages', {
95055                   languages: languageList
95056                 }));
95057               }
95058             }
95059
95060             function showNextEvents(selection) {
95061               var events = selection.append('div').attr('class', 'community-events');
95062               var item = events.selectAll('.community-event').data(nextEvents);
95063               var itemEnter = item.enter().append('div').attr('class', 'community-event');
95064               itemEnter.append('div').attr('class', 'community-event-name').append('a').attr('target', '_blank').attr('href', function (d) {
95065                 return d.url;
95066               }).html(function (d) {
95067                 var name = d.name;
95068
95069                 if (d.i18n && d.id) {
95070                   name = _t("community.".concat(communityID, ".events.").concat(d.id, ".name"), {
95071                     "default": name
95072                   });
95073                 }
95074
95075                 return name;
95076               });
95077               itemEnter.append('div').attr('class', 'community-event-when').html(function (d) {
95078                 var options = {
95079                   weekday: 'short',
95080                   day: 'numeric',
95081                   month: 'short',
95082                   year: 'numeric'
95083                 };
95084
95085                 if (d.date.getHours() || d.date.getMinutes()) {
95086                   // include time if it has one
95087                   options.hour = 'numeric';
95088                   options.minute = 'numeric';
95089                 }
95090
95091                 return d.date.toLocaleString(_mainLocalizer.localeCode(), options);
95092               });
95093               itemEnter.append('div').attr('class', 'community-event-where').html(function (d) {
95094                 var where = d.where;
95095
95096                 if (d.i18n && d.id) {
95097                   where = _t("community.".concat(communityID, ".events.").concat(d.id, ".where"), {
95098                     "default": where
95099                   });
95100                 }
95101
95102                 return where;
95103               });
95104               itemEnter.append('div').attr('class', 'community-event-description').html(function (d) {
95105                 var description = d.description;
95106
95107                 if (d.i18n && d.id) {
95108                   description = _t("community.".concat(communityID, ".events.").concat(d.id, ".description"), {
95109                     "default": description
95110                   });
95111                 }
95112
95113                 return description;
95114               });
95115             }
95116
95117             function linkify(url, text) {
95118               text = text || url;
95119               return "<a target=\"_blank\" href=\"".concat(url, "\">").concat(text, "</a>");
95120             }
95121           }
95122
95123           success.changeset = function (val) {
95124             if (!arguments.length) return _changeset;
95125             _changeset = val;
95126             return success;
95127           };
95128
95129           success.location = function (val) {
95130             if (!arguments.length) return _location;
95131             _location = val;
95132             return success;
95133           };
95134
95135           return utilRebind(success, dispatch$1, 'on');
95136         }
95137
95138         function modeSave(context) {
95139           var mode = {
95140             id: 'save'
95141           };
95142           var keybinding = utilKeybinding('modeSave');
95143           var commit = uiCommit(context).on('cancel', cancel);
95144
95145           var _conflictsUi; // uiConflicts
95146
95147
95148           var _location;
95149
95150           var _success;
95151
95152           var uploader = context.uploader().on('saveStarted.modeSave', function () {
95153             keybindingOff();
95154           }) // fire off some async work that we want to be ready later
95155           .on('willAttemptUpload.modeSave', prepareForSuccess).on('progressChanged.modeSave', showProgress).on('resultNoChanges.modeSave', function () {
95156             cancel();
95157           }).on('resultErrors.modeSave', showErrors).on('resultConflicts.modeSave', showConflicts).on('resultSuccess.modeSave', showSuccess);
95158
95159           function cancel() {
95160             context.enter(modeBrowse(context));
95161           }
95162
95163           function showProgress(num, total) {
95164             var modal = context.container().select('.loading-modal .modal-section');
95165             var progress = modal.selectAll('.progress').data([0]); // enter/update
95166
95167             progress.enter().append('div').attr('class', 'progress').merge(progress).text(_t('save.conflict_progress', {
95168               num: num,
95169               total: total
95170             }));
95171           }
95172
95173           function showConflicts(changeset, conflicts, origChanges) {
95174             var selection = context.container().select('.sidebar').append('div').attr('class', 'sidebar-component');
95175             context.container().selectAll('.main-content').classed('active', true).classed('inactive', false);
95176             _conflictsUi = uiConflicts(context).conflictList(conflicts).origChanges(origChanges).on('cancel', function () {
95177               context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
95178               selection.remove();
95179               keybindingOn();
95180               uploader.cancelConflictResolution();
95181             }).on('save', function () {
95182               context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
95183               selection.remove();
95184               uploader.processResolvedConflicts(changeset);
95185             });
95186             selection.call(_conflictsUi);
95187           }
95188
95189           function showErrors(errors) {
95190             keybindingOn();
95191             var selection = uiConfirm(context.container());
95192             selection.select('.modal-section.header').append('h3').text(_t('save.error'));
95193             addErrors(selection, errors);
95194             selection.okButton();
95195           }
95196
95197           function addErrors(selection, data) {
95198             var message = selection.select('.modal-section.message-text');
95199             var items = message.selectAll('.error-container').data(data);
95200             var enter = items.enter().append('div').attr('class', 'error-container');
95201             enter.append('a').attr('class', 'error-description').attr('href', '#').classed('hide-toggle', true).text(function (d) {
95202               return d.msg || _t('save.unknown_error_details');
95203             }).on('click', function (d3_event) {
95204               d3_event.preventDefault();
95205               var error = select(this);
95206               var detail = select(this.nextElementSibling);
95207               var exp = error.classed('expanded');
95208               detail.style('display', exp ? 'none' : 'block');
95209               error.classed('expanded', !exp);
95210             });
95211             var details = enter.append('div').attr('class', 'error-detail-container').style('display', 'none');
95212             details.append('ul').attr('class', 'error-detail-list').selectAll('li').data(function (d) {
95213               return d.details || [];
95214             }).enter().append('li').attr('class', 'error-detail-item').text(function (d) {
95215               return d;
95216             });
95217             items.exit().remove();
95218           }
95219
95220           function showSuccess(changeset) {
95221             commit.reset();
95222
95223             var ui = _success.changeset(changeset).location(_location).on('cancel', function () {
95224               context.ui().sidebar.hide();
95225             });
95226
95227             context.enter(modeBrowse(context).sidebar(ui));
95228           }
95229
95230           function keybindingOn() {
95231             select(document).call(keybinding.on('⎋', cancel, true));
95232           }
95233
95234           function keybindingOff() {
95235             select(document).call(keybinding.unbind);
95236           } // Reverse geocode current map location so we can display a message on
95237           // the success screen like "Thank you for editing around place, region."
95238
95239
95240           function prepareForSuccess() {
95241             _success = uiSuccess(context);
95242             _location = null;
95243             if (!services.geocoder) return;
95244             services.geocoder.reverse(context.map().center(), function (err, result) {
95245               if (err || !result || !result.address) return;
95246               var addr = result.address;
95247               var place = addr && (addr.town || addr.city || addr.county) || '';
95248               var region = addr && (addr.state || addr.country) || '';
95249               var separator = place && region ? _t('success.thank_you_where.separator') : '';
95250               _location = _t('success.thank_you_where.format', {
95251                 place: place,
95252                 separator: separator,
95253                 region: region
95254               });
95255             });
95256           }
95257
95258           mode.selectedIDs = function () {
95259             return _conflictsUi ? _conflictsUi.shownEntityIds() : [];
95260           };
95261
95262           mode.enter = function () {
95263             // Show sidebar
95264             context.ui().sidebar.expand();
95265
95266             function done() {
95267               context.ui().sidebar.show(commit);
95268             }
95269
95270             keybindingOn();
95271             context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
95272             var osm = context.connection();
95273
95274             if (!osm) {
95275               cancel();
95276               return;
95277             }
95278
95279             if (osm.authenticated()) {
95280               done();
95281             } else {
95282               osm.authenticate(function (err) {
95283                 if (err) {
95284                   cancel();
95285                 } else {
95286                   done();
95287                 }
95288               });
95289             }
95290           };
95291
95292           mode.exit = function () {
95293             keybindingOff();
95294             context.container().selectAll('.main-content').classed('active', true).classed('inactive', false);
95295             context.ui().sidebar.hide();
95296           };
95297
95298           return mode;
95299         }
95300
95301         function uiToolOldDrawModes(context) {
95302           var tool = {
95303             id: 'old_modes',
95304             label: _t.html('toolbar.add_feature')
95305           };
95306           var modes = [modeAddPoint(context, {
95307             title: _t.html('modes.add_point.title'),
95308             button: 'point',
95309             description: _t.html('modes.add_point.description'),
95310             preset: _mainPresetIndex.item('point'),
95311             key: '1'
95312           }), modeAddLine(context, {
95313             title: _t.html('modes.add_line.title'),
95314             button: 'line',
95315             description: _t.html('modes.add_line.description'),
95316             preset: _mainPresetIndex.item('line'),
95317             key: '2'
95318           }), modeAddArea(context, {
95319             title: _t.html('modes.add_area.title'),
95320             button: 'area',
95321             description: _t.html('modes.add_area.description'),
95322             preset: _mainPresetIndex.item('area'),
95323             key: '3'
95324           })];
95325
95326           function enabled() {
95327             return osmEditable();
95328           }
95329
95330           function osmEditable() {
95331             return context.editable();
95332           }
95333
95334           modes.forEach(function (mode) {
95335             context.keybinding().on(mode.key, function () {
95336               if (!enabled()) return;
95337
95338               if (mode.id === context.mode().id) {
95339                 context.enter(modeBrowse(context));
95340               } else {
95341                 context.enter(mode);
95342               }
95343             });
95344           });
95345
95346           tool.render = function (selection) {
95347             var wrap = selection.append('div').attr('class', 'joined').style('display', 'flex');
95348
95349             var debouncedUpdate = debounce(update, 500, {
95350               leading: true,
95351               trailing: true
95352             });
95353
95354             context.map().on('move.modes', debouncedUpdate).on('drawn.modes', debouncedUpdate);
95355             context.on('enter.modes', update);
95356             update();
95357
95358             function update() {
95359               var buttons = wrap.selectAll('button.add-button').data(modes, function (d) {
95360                 return d.id;
95361               }); // exit
95362
95363               buttons.exit().remove(); // enter
95364
95365               var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
95366                 return d.id + ' add-button bar-button';
95367               }).on('click.mode-buttons', function (d3_event, d) {
95368                 if (!enabled()) return; // When drawing, ignore accidental clicks on mode buttons - #4042
95369
95370                 var currMode = context.mode().id;
95371                 if (/^draw/.test(currMode)) return;
95372
95373                 if (d.id === currMode) {
95374                   context.enter(modeBrowse(context));
95375                 } else {
95376                   context.enter(d);
95377                 }
95378               }).call(uiTooltip().placement('bottom').title(function (d) {
95379                 return d.description;
95380               }).keys(function (d) {
95381                 return [d.key];
95382               }).scrollContainer(context.container().select('.top-toolbar')));
95383               buttonsEnter.each(function (d) {
95384                 select(this).call(svgIcon('#iD-icon-' + d.button));
95385               });
95386               buttonsEnter.append('span').attr('class', 'label').html(function (mode) {
95387                 return mode.title;
95388               }); // if we are adding/removing the buttons, check if toolbar has overflowed
95389
95390               if (buttons.enter().size() || buttons.exit().size()) {
95391                 context.ui().checkOverflow('.top-toolbar', true);
95392               } // update
95393
95394
95395               buttons = buttons.merge(buttonsEnter).classed('disabled', function (d) {
95396                 return !enabled();
95397               }).classed('active', function (d) {
95398                 return context.mode() && context.mode().button === d.button;
95399               });
95400             }
95401           };
95402
95403           return tool;
95404         }
95405
95406         function uiToolNotes(context) {
95407           var tool = {
95408             id: 'notes',
95409             label: _t.html('modes.add_note.label')
95410           };
95411           var mode = modeAddNote(context);
95412
95413           function enabled() {
95414             return notesEnabled() && notesEditable();
95415           }
95416
95417           function notesEnabled() {
95418             var noteLayer = context.layers().layer('notes');
95419             return noteLayer && noteLayer.enabled();
95420           }
95421
95422           function notesEditable() {
95423             var mode = context.mode();
95424             return context.map().notesEditable() && mode && mode.id !== 'save';
95425           }
95426
95427           context.keybinding().on(mode.key, function () {
95428             if (!enabled()) return;
95429
95430             if (mode.id === context.mode().id) {
95431               context.enter(modeBrowse(context));
95432             } else {
95433               context.enter(mode);
95434             }
95435           });
95436
95437           tool.render = function (selection) {
95438             var debouncedUpdate = debounce(update, 500, {
95439               leading: true,
95440               trailing: true
95441             });
95442
95443             context.map().on('move.notes', debouncedUpdate).on('drawn.notes', debouncedUpdate);
95444             context.on('enter.notes', update);
95445             update();
95446
95447             function update() {
95448               var showNotes = notesEnabled();
95449               var data = showNotes ? [mode] : [];
95450               var buttons = selection.selectAll('button.add-button').data(data, function (d) {
95451                 return d.id;
95452               }); // exit
95453
95454               buttons.exit().remove(); // enter
95455
95456               var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
95457                 return d.id + ' add-button bar-button';
95458               }).on('click.notes', function (d3_event, d) {
95459                 if (!enabled()) return; // When drawing, ignore accidental clicks on mode buttons - #4042
95460
95461                 var currMode = context.mode().id;
95462                 if (/^draw/.test(currMode)) return;
95463
95464                 if (d.id === currMode) {
95465                   context.enter(modeBrowse(context));
95466                 } else {
95467                   context.enter(d);
95468                 }
95469               }).call(uiTooltip().placement('bottom').title(function (d) {
95470                 return d.description;
95471               }).keys(function (d) {
95472                 return [d.key];
95473               }).scrollContainer(context.container().select('.top-toolbar')));
95474               buttonsEnter.each(function (d) {
95475                 select(this).call(svgIcon(d.icon || '#iD-icon-' + d.button));
95476               }); // if we are adding/removing the buttons, check if toolbar has overflowed
95477
95478               if (buttons.enter().size() || buttons.exit().size()) {
95479                 context.ui().checkOverflow('.top-toolbar', true);
95480               } // update
95481
95482
95483               buttons = buttons.merge(buttonsEnter).classed('disabled', function (d) {
95484                 return !enabled();
95485               }).classed('active', function (d) {
95486                 return context.mode() && context.mode().button === d.button;
95487               });
95488             }
95489           };
95490
95491           tool.uninstall = function () {
95492             context.on('enter.editor.notes', null).on('exit.editor.notes', null).on('enter.notes', null);
95493             context.map().on('move.notes', null).on('drawn.notes', null);
95494           };
95495
95496           return tool;
95497         }
95498
95499         function uiToolSave(context) {
95500           var tool = {
95501             id: 'save',
95502             label: _t.html('save.title')
95503           };
95504           var button = null;
95505           var tooltipBehavior = null;
95506           var history = context.history();
95507           var key = uiCmd('⌘S');
95508           var _numChanges = 0;
95509
95510           function isSaving() {
95511             var mode = context.mode();
95512             return mode && mode.id === 'save';
95513           }
95514
95515           function isDisabled() {
95516             return _numChanges === 0 || isSaving();
95517           }
95518
95519           function save(d3_event) {
95520             d3_event.preventDefault();
95521
95522             if (!context.inIntro() && !isSaving() && history.hasChanges()) {
95523               context.enter(modeSave(context));
95524             }
95525           }
95526
95527           function bgColor() {
95528             var step;
95529
95530             if (_numChanges === 0) {
95531               return null;
95532             } else if (_numChanges <= 50) {
95533               step = _numChanges / 50;
95534               return d3_interpolateRgb('#fff', '#ff8')(step); // white -> yellow
95535             } else {
95536               step = Math.min((_numChanges - 50) / 50, 1.0);
95537               return d3_interpolateRgb('#ff8', '#f88')(step); // yellow -> red
95538             }
95539           }
95540
95541           function updateCount() {
95542             var val = history.difference().summary().length;
95543             if (val === _numChanges) return;
95544             _numChanges = val;
95545
95546             if (tooltipBehavior) {
95547               tooltipBehavior.title(_t.html(_numChanges > 0 ? 'save.help' : 'save.no_changes')).keys([key]);
95548             }
95549
95550             if (button) {
95551               button.classed('disabled', isDisabled()).style('background', bgColor());
95552               button.select('span.count').html(_numChanges);
95553             }
95554           }
95555
95556           tool.render = function (selection) {
95557             tooltipBehavior = uiTooltip().placement('bottom').title(_t.html('save.no_changes')).keys([key]).scrollContainer(context.container().select('.top-toolbar'));
95558             var lastPointerUpType;
95559             button = selection.append('button').attr('class', 'save disabled bar-button').on('pointerup', function (d3_event) {
95560               lastPointerUpType = d3_event.pointerType;
95561             }).on('click', function (d3_event) {
95562               save(d3_event);
95563
95564               if (_numChanges === 0 && (lastPointerUpType === 'touch' || lastPointerUpType === 'pen')) {
95565                 // there are no tooltips for touch interactions so flash feedback instead
95566                 context.ui().flash.duration(2000).iconName('#iD-icon-save').iconClass('disabled').label(_t.html('save.no_changes'))();
95567               }
95568
95569               lastPointerUpType = null;
95570             }).call(tooltipBehavior);
95571             button.call(svgIcon('#iD-icon-save'));
95572             button.append('span').attr('class', 'count').attr('aria-hidden', 'true').html('0');
95573             updateCount();
95574             context.keybinding().on(key, save, true);
95575             context.history().on('change.save', updateCount);
95576             context.on('enter.save', function () {
95577               if (button) {
95578                 button.classed('disabled', isDisabled());
95579
95580                 if (isSaving()) {
95581                   button.call(tooltipBehavior.hide);
95582                 }
95583               }
95584             });
95585           };
95586
95587           tool.uninstall = function () {
95588             context.keybinding().off(key, true);
95589             context.history().on('change.save', null);
95590             context.on('enter.save', null);
95591             button = null;
95592             tooltipBehavior = null;
95593           };
95594
95595           return tool;
95596         }
95597
95598         function uiToolSidebarToggle(context) {
95599           var tool = {
95600             id: 'sidebar_toggle',
95601             label: _t.html('toolbar.inspect')
95602           };
95603
95604           tool.render = function (selection) {
95605             selection.append('button').attr('class', 'bar-button').on('click', function () {
95606               context.ui().sidebar.toggle();
95607             }).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')));
95608           };
95609
95610           return tool;
95611         }
95612
95613         function uiToolUndoRedo(context) {
95614           var tool = {
95615             id: 'undo_redo',
95616             label: _t.html('toolbar.undo_redo')
95617           };
95618           var commands = [{
95619             id: 'undo',
95620             cmd: uiCmd('⌘Z'),
95621             action: function action() {
95622               context.undo();
95623             },
95624             annotation: function annotation() {
95625               return context.history().undoAnnotation();
95626             },
95627             icon: 'iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo')
95628           }, {
95629             id: 'redo',
95630             cmd: uiCmd('⌘⇧Z'),
95631             action: function action() {
95632               context.redo();
95633             },
95634             annotation: function annotation() {
95635               return context.history().redoAnnotation();
95636             },
95637             icon: 'iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'undo' : 'redo')
95638           }];
95639
95640           function editable() {
95641             return context.mode() && context.mode().id !== 'save' && context.map().editableDataEnabled(true
95642             /* ignore min zoom */
95643             );
95644           }
95645
95646           tool.render = function (selection) {
95647             var tooltipBehavior = uiTooltip().placement('bottom').title(function (d) {
95648               return d.annotation() ? _t.html(d.id + '.tooltip', {
95649                 action: d.annotation()
95650               }) : _t.html(d.id + '.nothing');
95651             }).keys(function (d) {
95652               return [d.cmd];
95653             }).scrollContainer(context.container().select('.top-toolbar'));
95654             var lastPointerUpType;
95655             var buttons = selection.selectAll('button').data(commands).enter().append('button').attr('class', function (d) {
95656               return 'disabled ' + d.id + '-button bar-button';
95657             }).on('pointerup', function (d3_event) {
95658               // `pointerup` is always called before `click`
95659               lastPointerUpType = d3_event.pointerType;
95660             }).on('click', function (d3_event, d) {
95661               d3_event.preventDefault();
95662               var annotation = d.annotation();
95663
95664               if (editable() && annotation) {
95665                 d.action();
95666               }
95667
95668               if (editable() && (lastPointerUpType === 'touch' || lastPointerUpType === 'pen')) {
95669                 // there are no tooltips for touch interactions so flash feedback instead
95670                 var text = annotation ? _t(d.id + '.tooltip', {
95671                   action: annotation
95672                 }) : _t(d.id + '.nothing');
95673                 context.ui().flash.duration(2000).iconName('#' + d.icon).iconClass(annotation ? '' : 'disabled').label(text)();
95674               }
95675
95676               lastPointerUpType = null;
95677             }).call(tooltipBehavior);
95678             buttons.each(function (d) {
95679               select(this).call(svgIcon('#' + d.icon));
95680             });
95681             context.keybinding().on(commands[0].cmd, function (d3_event) {
95682               d3_event.preventDefault();
95683               if (editable()) commands[0].action();
95684             }).on(commands[1].cmd, function (d3_event) {
95685               d3_event.preventDefault();
95686               if (editable()) commands[1].action();
95687             });
95688
95689             var debouncedUpdate = debounce(update, 500, {
95690               leading: true,
95691               trailing: true
95692             });
95693
95694             context.map().on('move.undo_redo', debouncedUpdate).on('drawn.undo_redo', debouncedUpdate);
95695             context.history().on('change.undo_redo', function (difference) {
95696               if (difference) update();
95697             });
95698             context.on('enter.undo_redo', update);
95699
95700             function update() {
95701               buttons.classed('disabled', function (d) {
95702                 return !editable() || !d.annotation();
95703               }).each(function () {
95704                 var selection = select(this);
95705
95706                 if (!selection.select('.tooltip.in').empty()) {
95707                   selection.call(tooltipBehavior.updateContent);
95708                 }
95709               });
95710             }
95711           };
95712
95713           tool.uninstall = function () {
95714             context.keybinding().off(commands[0].cmd).off(commands[1].cmd);
95715             context.map().on('move.undo_redo', null).on('drawn.undo_redo', null);
95716             context.history().on('change.undo_redo', null);
95717             context.on('enter.undo_redo', null);
95718           };
95719
95720           return tool;
95721         }
95722
95723         function uiTopToolbar(context) {
95724           var sidebarToggle = uiToolSidebarToggle(context),
95725               modes = uiToolOldDrawModes(context),
95726               notes = uiToolNotes(context),
95727               undoRedo = uiToolUndoRedo(context),
95728               save = uiToolSave(context);
95729
95730           function notesEnabled() {
95731             var noteLayer = context.layers().layer('notes');
95732             return noteLayer && noteLayer.enabled();
95733           }
95734
95735           function topToolbar(bar) {
95736             bar.on('wheel.topToolbar', function (d3_event) {
95737               if (!d3_event.deltaX) {
95738                 // translate vertical scrolling into horizontal scrolling in case
95739                 // the user doesn't have an input device that can scroll horizontally
95740                 bar.node().scrollLeft += d3_event.deltaY;
95741               }
95742             });
95743
95744             var debouncedUpdate = debounce(update, 500, {
95745               leading: true,
95746               trailing: true
95747             });
95748
95749             context.layers().on('change.topToolbar', debouncedUpdate);
95750             update();
95751
95752             function update() {
95753               var tools = [sidebarToggle, 'spacer', modes];
95754               tools.push('spacer');
95755
95756               if (notesEnabled()) {
95757                 tools = tools.concat([notes, 'spacer']);
95758               }
95759
95760               tools = tools.concat([undoRedo, save]);
95761               var toolbarItems = bar.selectAll('.toolbar-item').data(tools, function (d) {
95762                 return d.id || d;
95763               });
95764               toolbarItems.exit().each(function (d) {
95765                 if (d.uninstall) {
95766                   d.uninstall();
95767                 }
95768               }).remove();
95769               var itemsEnter = toolbarItems.enter().append('div').attr('class', function (d) {
95770                 var classes = 'toolbar-item ' + (d.id || d).replace('_', '-');
95771                 if (d.klass) classes += ' ' + d.klass;
95772                 return classes;
95773               });
95774               var actionableItems = itemsEnter.filter(function (d) {
95775                 return d !== 'spacer';
95776               });
95777               actionableItems.append('div').attr('class', 'item-content').each(function (d) {
95778                 select(this).call(d.render, bar);
95779               });
95780               actionableItems.append('div').attr('class', 'item-label').html(function (d) {
95781                 return d.label;
95782               });
95783             }
95784           }
95785
95786           return topToolbar;
95787         }
95788
95789         var sawVersion = null;
95790         var isNewVersion = false;
95791         var isNewUser = false;
95792         function uiVersion(context) {
95793           var currVersion = context.version;
95794           var matchedVersion = currVersion.match(/\d+\.\d+\.\d+.*/);
95795
95796           if (sawVersion === null && matchedVersion !== null) {
95797             if (corePreferences('sawVersion')) {
95798               isNewUser = false;
95799               isNewVersion = corePreferences('sawVersion') !== currVersion && currVersion.indexOf('-') === -1;
95800             } else {
95801               isNewUser = true;
95802               isNewVersion = true;
95803             }
95804
95805             corePreferences('sawVersion', currVersion);
95806             sawVersion = currVersion;
95807           }
95808
95809           return function (selection) {
95810             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
95811
95812             if (isNewVersion && !isNewUser) {
95813               selection.append('a').attr('class', 'badge').attr('target', '_blank').attr('href', 'https://github.com/openstreetmap/iD/blob/release/CHANGELOG.md#whats-new').call(svgIcon('#maki-gift-11')).call(uiTooltip().title(_t.html('version.whats_new', {
95814                 version: currVersion
95815               })).placement('top').scrollContainer(context.container().select('.main-footer-wrap')));
95816             }
95817           };
95818         }
95819
95820         function uiZoom(context) {
95821           var zooms = [{
95822             id: 'zoom-in',
95823             icon: 'iD-icon-plus',
95824             title: _t.html('zoom.in'),
95825             action: zoomIn,
95826             disabled: function disabled() {
95827               return !context.map().canZoomIn();
95828             },
95829             disabledTitle: _t.html('zoom.disabled.in'),
95830             key: '+'
95831           }, {
95832             id: 'zoom-out',
95833             icon: 'iD-icon-minus',
95834             title: _t.html('zoom.out'),
95835             action: zoomOut,
95836             disabled: function disabled() {
95837               return !context.map().canZoomOut();
95838             },
95839             disabledTitle: _t.html('zoom.disabled.out'),
95840             key: '-'
95841           }];
95842
95843           function zoomIn(d3_event) {
95844             if (d3_event.shiftKey) return;
95845             d3_event.preventDefault();
95846             context.map().zoomIn();
95847           }
95848
95849           function zoomOut(d3_event) {
95850             if (d3_event.shiftKey) return;
95851             d3_event.preventDefault();
95852             context.map().zoomOut();
95853           }
95854
95855           function zoomInFurther(d3_event) {
95856             if (d3_event.shiftKey) return;
95857             d3_event.preventDefault();
95858             context.map().zoomInFurther();
95859           }
95860
95861           function zoomOutFurther(d3_event) {
95862             if (d3_event.shiftKey) return;
95863             d3_event.preventDefault();
95864             context.map().zoomOutFurther();
95865           }
95866
95867           return function (selection) {
95868             var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(function (d) {
95869               if (d.disabled()) {
95870                 return d.disabledTitle;
95871               }
95872
95873               return d.title;
95874             }).keys(function (d) {
95875               return [d.key];
95876             });
95877             var lastPointerUpType;
95878             var buttons = selection.selectAll('button').data(zooms).enter().append('button').attr('class', function (d) {
95879               return d.id;
95880             }).on('pointerup.editor', function (d3_event) {
95881               lastPointerUpType = d3_event.pointerType;
95882             }).on('click.editor', function (d3_event, d) {
95883               if (!d.disabled()) {
95884                 d.action(d3_event);
95885               } else if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
95886                 context.ui().flash.duration(2000).iconName('#' + d.icon).iconClass('disabled').label(d.disabledTitle)();
95887               }
95888
95889               lastPointerUpType = null;
95890             }).call(tooltipBehavior);
95891             buttons.each(function (d) {
95892               select(this).call(svgIcon('#' + d.icon, 'light'));
95893             });
95894             utilKeybinding.plusKeys.forEach(function (key) {
95895               context.keybinding().on([key], zoomIn);
95896               context.keybinding().on([uiCmd('⌥' + key)], zoomInFurther);
95897             });
95898             utilKeybinding.minusKeys.forEach(function (key) {
95899               context.keybinding().on([key], zoomOut);
95900               context.keybinding().on([uiCmd('⌥' + key)], zoomOutFurther);
95901             });
95902
95903             function updateButtonStates() {
95904               buttons.classed('disabled', function (d) {
95905                 return d.disabled();
95906               }).each(function () {
95907                 var selection = select(this);
95908
95909                 if (!selection.select('.tooltip.in').empty()) {
95910                   selection.call(tooltipBehavior.updateContent);
95911                 }
95912               });
95913             }
95914
95915             updateButtonStates();
95916             context.map().on('move.uiZoom', updateButtonStates);
95917           };
95918         }
95919
95920         function uiZoomToSelection(context) {
95921           function isDisabled() {
95922             var mode = context.mode();
95923             return !mode || !mode.zoomToSelected;
95924           }
95925
95926           var _lastPointerUpType;
95927
95928           function pointerup(d3_event) {
95929             _lastPointerUpType = d3_event.pointerType;
95930           }
95931
95932           function click(d3_event) {
95933             d3_event.preventDefault();
95934
95935             if (isDisabled()) {
95936               if (_lastPointerUpType === 'touch' || _lastPointerUpType === 'pen') {
95937                 context.ui().flash.duration(2000).iconName('#iD-icon-framed-dot').iconClass('disabled').label(_t.html('inspector.zoom_to.no_selection'))();
95938               }
95939             } else {
95940               var mode = context.mode();
95941
95942               if (mode && mode.zoomToSelected) {
95943                 mode.zoomToSelected();
95944               }
95945             }
95946
95947             _lastPointerUpType = null;
95948           }
95949
95950           return function (selection) {
95951             var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(function () {
95952               if (isDisabled()) {
95953                 return _t.html('inspector.zoom_to.no_selection');
95954               }
95955
95956               return _t.html('inspector.zoom_to.title');
95957             }).keys([_t('inspector.zoom_to.key')]);
95958             var button = selection.append('button').on('pointerup', pointerup).on('click', click).call(svgIcon('#iD-icon-framed-dot', 'light')).call(tooltipBehavior);
95959
95960             function setEnabledState() {
95961               button.classed('disabled', isDisabled());
95962
95963               if (!button.select('.tooltip.in').empty()) {
95964                 button.call(tooltipBehavior.updateContent);
95965               }
95966             }
95967
95968             context.on('enter.uiZoomToSelection', setEnabledState);
95969             setEnabledState();
95970           };
95971         }
95972
95973         function uiPane(id, context) {
95974           var _key;
95975
95976           var _label = '';
95977           var _description = '';
95978           var _iconName = '';
95979
95980           var _sections; // array of uiSection objects
95981
95982
95983           var _paneSelection = select(null);
95984
95985           var _paneTooltip;
95986
95987           var pane = {
95988             id: id
95989           };
95990
95991           pane.label = function (val) {
95992             if (!arguments.length) return _label;
95993             _label = val;
95994             return pane;
95995           };
95996
95997           pane.key = function (val) {
95998             if (!arguments.length) return _key;
95999             _key = val;
96000             return pane;
96001           };
96002
96003           pane.description = function (val) {
96004             if (!arguments.length) return _description;
96005             _description = val;
96006             return pane;
96007           };
96008
96009           pane.iconName = function (val) {
96010             if (!arguments.length) return _iconName;
96011             _iconName = val;
96012             return pane;
96013           };
96014
96015           pane.sections = function (val) {
96016             if (!arguments.length) return _sections;
96017             _sections = val;
96018             return pane;
96019           };
96020
96021           pane.selection = function () {
96022             return _paneSelection;
96023           };
96024
96025           function hidePane() {
96026             context.ui().togglePanes();
96027           }
96028
96029           pane.togglePane = function (d3_event) {
96030             if (d3_event) d3_event.preventDefault();
96031
96032             _paneTooltip.hide();
96033
96034             context.ui().togglePanes(!_paneSelection.classed('shown') ? _paneSelection : undefined);
96035           };
96036
96037           pane.renderToggleButton = function (selection) {
96038             if (!_paneTooltip) {
96039               _paneTooltip = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(_description).keys([_key]);
96040             }
96041
96042             selection.append('button').on('click', pane.togglePane).call(svgIcon('#' + _iconName, 'light')).call(_paneTooltip);
96043           };
96044
96045           pane.renderContent = function (selection) {
96046             // override to fully customize content
96047             if (_sections) {
96048               _sections.forEach(function (section) {
96049                 selection.call(section.render);
96050               });
96051             }
96052           };
96053
96054           pane.renderPane = function (selection) {
96055             _paneSelection = selection.append('div').attr('class', 'fillL map-pane hide ' + id + '-pane').attr('pane', id);
96056
96057             var heading = _paneSelection.append('div').attr('class', 'pane-heading');
96058
96059             heading.append('h2').html(_label);
96060             heading.append('button').on('click', hidePane).call(svgIcon('#iD-icon-close'));
96061
96062             _paneSelection.append('div').attr('class', 'pane-content').call(pane.renderContent);
96063
96064             if (_key) {
96065               context.keybinding().on(_key, pane.togglePane);
96066             }
96067           };
96068
96069           return pane;
96070         }
96071
96072         function uiSectionBackgroundDisplayOptions(context) {
96073           var section = uiSection('background-display-options', context).label(_t.html('background.display_options')).disclosureContent(renderDisclosureContent);
96074
96075           var _detected = utilDetect();
96076
96077           var _storedOpacity = corePreferences('background-opacity');
96078
96079           var _minVal = 0;
96080
96081           var _maxVal = _detected.cssfilters ? 3 : 1;
96082
96083           var _sliders = _detected.cssfilters ? ['brightness', 'contrast', 'saturation', 'sharpness'] : ['brightness'];
96084
96085           var _options = {
96086             brightness: _storedOpacity !== null ? +_storedOpacity : 1,
96087             contrast: 1,
96088             saturation: 1,
96089             sharpness: 1
96090           };
96091
96092           function clamp(x, min, max) {
96093             return Math.max(min, Math.min(x, max));
96094           }
96095
96096           function updateValue(d, val) {
96097             val = clamp(val, _minVal, _maxVal);
96098             _options[d] = val;
96099             context.background()[d](val);
96100
96101             if (d === 'brightness') {
96102               corePreferences('background-opacity', val);
96103             }
96104
96105             section.reRender();
96106           }
96107
96108           function renderDisclosureContent(selection) {
96109             var container = selection.selectAll('.display-options-container').data([0]);
96110             var containerEnter = container.enter().append('div').attr('class', 'display-options-container controls-list'); // add slider controls
96111
96112             var slidersEnter = containerEnter.selectAll('.display-control').data(_sliders).enter().append('div').attr('class', function (d) {
96113               return 'display-control display-control-' + d;
96114             });
96115             slidersEnter.append('h5').html(function (d) {
96116               return _t.html('background.' + d);
96117             }).append('span').attr('class', function (d) {
96118               return 'display-option-value display-option-value-' + d;
96119             });
96120             var sildersControlEnter = slidersEnter.append('div').attr('class', 'control-wrap');
96121             sildersControlEnter.append('input').attr('class', function (d) {
96122               return 'display-option-input display-option-input-' + d;
96123             }).attr('type', 'range').attr('min', _minVal).attr('max', _maxVal).attr('step', '0.05').on('input', function (d3_event, d) {
96124               var val = select(this).property('value');
96125
96126               if (!val && d3_event && d3_event.target) {
96127                 val = d3_event.target.value;
96128               }
96129
96130               updateValue(d, val);
96131             });
96132             sildersControlEnter.append('button').attr('title', _t('background.reset')).attr('class', function (d) {
96133               return 'display-option-reset display-option-reset-' + d;
96134             }).on('click', function (d3_event, d) {
96135               if (d3_event.button !== 0) return;
96136               updateValue(d, 1);
96137             }).call(svgIcon('#iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo'))); // reset all button
96138
96139             containerEnter.append('a').attr('class', 'display-option-resetlink').attr('href', '#').html(_t.html('background.reset_all')).on('click', function (d3_event) {
96140               d3_event.preventDefault();
96141
96142               for (var i = 0; i < _sliders.length; i++) {
96143                 updateValue(_sliders[i], 1);
96144               }
96145             }); // update
96146
96147             container = containerEnter.merge(container);
96148             container.selectAll('.display-option-input').property('value', function (d) {
96149               return _options[d];
96150             });
96151             container.selectAll('.display-option-value').html(function (d) {
96152               return Math.floor(_options[d] * 100) + '%';
96153             });
96154             container.selectAll('.display-option-reset').classed('disabled', function (d) {
96155               return _options[d] === 1;
96156             }); // first time only, set brightness if needed
96157
96158             if (containerEnter.size() && _options.brightness !== 1) {
96159               context.background().brightness(_options.brightness);
96160             }
96161           }
96162
96163           return section;
96164         }
96165
96166         function uiSettingsCustomBackground() {
96167           var dispatch$1 = dispatch('change');
96168
96169           function render(selection) {
96170             // keep separate copies of original and current settings
96171             var _origSettings = {
96172               template: corePreferences('background-custom-template')
96173             };
96174             var _currSettings = {
96175               template: corePreferences('background-custom-template')
96176             };
96177             var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
96178             var modal = uiConfirm(selection).okButton();
96179             modal.classed('settings-modal settings-custom-background', true);
96180             modal.select('.modal-section.header').append('h3').html(_t.html('settings.custom_background.header'));
96181             var textSection = modal.select('.modal-section.message-text');
96182             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, "`");
96183             textSection.append('div').attr('class', 'instructions-template').html(marked_1(instructions));
96184             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
96185
96186             var buttonSection = modal.select('.modal-section.buttons');
96187             buttonSection.insert('button', '.ok-button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
96188             buttonSection.select('.cancel-button').on('click.cancel', clickCancel);
96189             buttonSection.select('.ok-button').attr('disabled', isSaveDisabled).on('click.save', clickSave);
96190
96191             function isSaveDisabled() {
96192               return null;
96193             } // restore the original template
96194
96195
96196             function clickCancel() {
96197               textSection.select('.field-template').property('value', _origSettings.template);
96198               corePreferences('background-custom-template', _origSettings.template);
96199               this.blur();
96200               modal.close();
96201             } // accept the current template
96202
96203
96204             function clickSave() {
96205               _currSettings.template = textSection.select('.field-template').property('value');
96206               corePreferences('background-custom-template', _currSettings.template);
96207               this.blur();
96208               modal.close();
96209               dispatch$1.call('change', this, _currSettings);
96210             }
96211           }
96212
96213           return utilRebind(render, dispatch$1, 'on');
96214         }
96215
96216         function uiSectionBackgroundList(context) {
96217           var _backgroundList = select(null);
96218
96219           var _customSource = context.background().findSource('custom');
96220
96221           var _settingsCustomBackground = uiSettingsCustomBackground().on('change', customChanged);
96222
96223           var section = uiSection('background-list', context).label(_t.html('background.backgrounds')).disclosureContent(renderDisclosureContent);
96224
96225           function previousBackgroundID() {
96226             return corePreferences('background-last-used-toggle');
96227           }
96228
96229           function renderDisclosureContent(selection) {
96230             // the background list
96231             var container = selection.selectAll('.layer-background-list').data([0]);
96232             _backgroundList = container.enter().append('ul').attr('class', 'layer-list layer-background-list').attr('dir', 'auto').merge(container); // add minimap toggle below list
96233
96234             var bgExtrasListEnter = selection.selectAll('.bg-extras-list').data([0]).enter().append('ul').attr('class', 'layer-list bg-extras-list');
96235             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'));
96236             minimapLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
96237               d3_event.preventDefault();
96238               uiMapInMap.toggle();
96239             });
96240             minimapLabelEnter.append('span').html(_t.html('background.minimap.description'));
96241             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'));
96242             panelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
96243               d3_event.preventDefault();
96244               context.ui().info.toggle('background');
96245             });
96246             panelLabelEnter.append('span').html(_t.html('background.panel.description'));
96247             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'));
96248             locPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
96249               d3_event.preventDefault();
96250               context.ui().info.toggle('location');
96251             });
96252             locPanelLabelEnter.append('span').html(_t.html('background.location_panel.description')); // "Info / Report a Problem" link
96253
96254             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'));
96255
96256             _backgroundList.call(drawListItems, 'radio', function (d3_event, d) {
96257               chooseBackground(d);
96258             }, function (d) {
96259               return !d.isHidden() && !d.overlay;
96260             });
96261           }
96262
96263           function setTooltips(selection) {
96264             selection.each(function (d, i, nodes) {
96265               var item = select(this).select('label');
96266               var span = item.select('span');
96267               var placement = i < nodes.length / 2 ? 'bottom' : 'top';
96268               var description = d.description();
96269               var isOverflowing = span.property('clientWidth') !== span.property('scrollWidth');
96270               item.call(uiTooltip().destroyAny);
96271
96272               if (d.id === previousBackgroundID()) {
96273                 item.call(uiTooltip().placement(placement).title('<div>' + _t.html('background.switch') + '</div>').keys([uiCmd('⌘' + _t('background.key'))]));
96274               } else if (description || isOverflowing) {
96275                 item.call(uiTooltip().placement(placement).title(description || d.label()));
96276               }
96277             });
96278           }
96279
96280           function drawListItems(layerList, type, change, filter) {
96281             var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter).sort(function (a, b) {
96282               return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : d3_descending(a.area(), b.area()) || d3_ascending(a.name(), b.name()) || 0;
96283             });
96284             var layerLinks = layerList.selectAll('li') // We have to be a bit inefficient about reordering the list since
96285             // arrow key navigation of radio values likes to work in the order
96286             // they were added, not the display document order.
96287             .data(sources, function (d, i) {
96288               return d.id + '---' + i;
96289             });
96290             layerLinks.exit().remove();
96291             var enter = layerLinks.enter().append('li').classed('layer-custom', function (d) {
96292               return d.id === 'custom';
96293             }).classed('best', function (d) {
96294               return d.best();
96295             });
96296             var label = enter.append('label');
96297             label.append('input').attr('type', type).attr('name', 'background-layer').attr('value', function (d) {
96298               return d.id;
96299             }).on('change', change);
96300             label.append('span').html(function (d) {
96301               return d.label();
96302             });
96303             enter.filter(function (d) {
96304               return d.id === 'custom';
96305             }).append('button').attr('class', 'layer-browse').call(uiTooltip().title(_t.html('settings.custom_background.tooltip')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).on('click', function (d3_event) {
96306               d3_event.preventDefault();
96307               editCustom();
96308             }).call(svgIcon('#iD-icon-more'));
96309             enter.filter(function (d) {
96310               return d.best();
96311             }).append('div').attr('class', 'best').call(uiTooltip().title(_t.html('background.best_imagery')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).append('span').html('&#9733;');
96312             layerList.call(updateLayerSelections);
96313           }
96314
96315           function updateLayerSelections(selection) {
96316             function active(d) {
96317               return context.background().showsLayer(d);
96318             }
96319
96320             selection.selectAll('li').classed('active', active).classed('switch', function (d) {
96321               return d.id === previousBackgroundID();
96322             }).call(setTooltips).selectAll('input').property('checked', active);
96323           }
96324
96325           function chooseBackground(d) {
96326             if (d.id === 'custom' && !d.template()) {
96327               return editCustom();
96328             }
96329
96330             var previousBackground = context.background().baseLayerSource();
96331             corePreferences('background-last-used-toggle', previousBackground.id);
96332             corePreferences('background-last-used', d.id);
96333             context.background().baseLayerSource(d);
96334           }
96335
96336           function customChanged(d) {
96337             if (d && d.template) {
96338               _customSource.template(d.template);
96339
96340               chooseBackground(_customSource);
96341             } else {
96342               _customSource.template('');
96343
96344               chooseBackground(context.background().findSource('none'));
96345             }
96346           }
96347
96348           function editCustom() {
96349             context.container().call(_settingsCustomBackground);
96350           }
96351
96352           context.background().on('change.background_list', function () {
96353             _backgroundList.call(updateLayerSelections);
96354           });
96355           context.map().on('move.background_list', debounce(function () {
96356             // layers in-view may have changed due to map move
96357             window.requestIdleCallback(section.reRender);
96358           }, 1000));
96359           return section;
96360         }
96361
96362         function uiSectionBackgroundOffset(context) {
96363           var section = uiSection('background-offset', context).label(_t.html('background.fix_misalignment')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
96364
96365           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
96366
96367           var _directions = [['top', [0, -0.5]], ['left', [-0.5, 0]], ['right', [0.5, 0]], ['bottom', [0, 0.5]]];
96368
96369           function updateValue() {
96370             var meters = geoOffsetToMeters(context.background().offset());
96371             var x = +meters[0].toFixed(2);
96372             var y = +meters[1].toFixed(2);
96373             context.container().selectAll('.nudge-inner-rect').select('input').classed('error', false).property('value', x + ', ' + y);
96374             context.container().selectAll('.nudge-reset').classed('disabled', function () {
96375               return x === 0 && y === 0;
96376             });
96377           }
96378
96379           function resetOffset() {
96380             context.background().offset([0, 0]);
96381             updateValue();
96382           }
96383
96384           function nudge(d) {
96385             context.background().nudge(d, context.map().zoom());
96386             updateValue();
96387           }
96388
96389           function inputOffset() {
96390             var input = select(this);
96391             var d = input.node().value;
96392             if (d === '') return resetOffset();
96393             d = d.replace(/;/g, ',').split(',').map(function (n) {
96394               // if n is NaN, it will always get mapped to false.
96395               return !isNaN(n) && n;
96396             });
96397
96398             if (d.length !== 2 || !d[0] || !d[1]) {
96399               input.classed('error', true);
96400               return;
96401             }
96402
96403             context.background().offset(geoMetersToOffset(d));
96404             updateValue();
96405           }
96406
96407           function dragOffset(d3_event) {
96408             if (d3_event.button !== 0) return;
96409             var origin = [d3_event.clientX, d3_event.clientY];
96410             var pointerId = d3_event.pointerId || 'mouse';
96411             context.container().append('div').attr('class', 'nudge-surface');
96412             select(window).on(_pointerPrefix + 'move.drag-bg-offset', pointermove).on(_pointerPrefix + 'up.drag-bg-offset', pointerup);
96413
96414             if (_pointerPrefix === 'pointer') {
96415               select(window).on('pointercancel.drag-bg-offset', pointerup);
96416             }
96417
96418             function pointermove(d3_event) {
96419               if (pointerId !== (d3_event.pointerId || 'mouse')) return;
96420               var latest = [d3_event.clientX, d3_event.clientY];
96421               var d = [-(origin[0] - latest[0]) / 4, -(origin[1] - latest[1]) / 4];
96422               origin = latest;
96423               nudge(d);
96424             }
96425
96426             function pointerup(d3_event) {
96427               if (pointerId !== (d3_event.pointerId || 'mouse')) return;
96428               if (d3_event.button !== 0) return;
96429               context.container().selectAll('.nudge-surface').remove();
96430               select(window).on('.drag-bg-offset', null);
96431             }
96432           }
96433
96434           function renderDisclosureContent(selection) {
96435             var container = selection.selectAll('.nudge-container').data([0]);
96436             var containerEnter = container.enter().append('div').attr('class', 'nudge-container');
96437             containerEnter.append('div').attr('class', 'nudge-instructions').html(_t.html('background.offset'));
96438             var nudgeWrapEnter = containerEnter.append('div').attr('class', 'nudge-controls-wrap');
96439             var nudgeEnter = nudgeWrapEnter.append('div').attr('class', 'nudge-outer-rect').on(_pointerPrefix + 'down', dragOffset);
96440             nudgeEnter.append('div').attr('class', 'nudge-inner-rect').append('input').attr('type', 'text').on('change', inputOffset);
96441             nudgeWrapEnter.append('div').selectAll('button').data(_directions).enter().append('button').attr('class', function (d) {
96442               return d[0] + ' nudge';
96443             }).on('click', function (d3_event, d) {
96444               nudge(d[1]);
96445             });
96446             nudgeWrapEnter.append('button').attr('title', _t('background.reset')).attr('class', 'nudge-reset disabled').on('click', function (d3_event) {
96447               d3_event.preventDefault();
96448               resetOffset();
96449             }).call(svgIcon('#iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo')));
96450             updateValue();
96451           }
96452
96453           context.background().on('change.backgroundOffset-update', updateValue);
96454           return section;
96455         }
96456
96457         function uiSectionOverlayList(context) {
96458           var section = uiSection('overlay-list', context).label(_t.html('background.overlays')).disclosureContent(renderDisclosureContent);
96459
96460           var _overlayList = select(null);
96461
96462           function setTooltips(selection) {
96463             selection.each(function (d, i, nodes) {
96464               var item = select(this).select('label');
96465               var span = item.select('span');
96466               var placement = i < nodes.length / 2 ? 'bottom' : 'top';
96467               var description = d.description();
96468               var isOverflowing = span.property('clientWidth') !== span.property('scrollWidth');
96469               item.call(uiTooltip().destroyAny);
96470
96471               if (description || isOverflowing) {
96472                 item.call(uiTooltip().placement(placement).title(description || d.name()));
96473               }
96474             });
96475           }
96476
96477           function updateLayerSelections(selection) {
96478             function active(d) {
96479               return context.background().showsLayer(d);
96480             }
96481
96482             selection.selectAll('li').classed('active', active).call(setTooltips).selectAll('input').property('checked', active);
96483           }
96484
96485           function chooseOverlay(d3_event, d) {
96486             d3_event.preventDefault();
96487             context.background().toggleOverlayLayer(d);
96488
96489             _overlayList.call(updateLayerSelections);
96490
96491             document.activeElement.blur();
96492           }
96493
96494           function drawListItems(layerList, type, change, filter) {
96495             var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter);
96496             var layerLinks = layerList.selectAll('li').data(sources, function (d) {
96497               return d.name();
96498             });
96499             layerLinks.exit().remove();
96500             var enter = layerLinks.enter().append('li');
96501             var label = enter.append('label');
96502             label.append('input').attr('type', type).attr('name', 'layers').on('change', change);
96503             label.append('span').html(function (d) {
96504               return d.label();
96505             });
96506             layerList.selectAll('li').sort(sortSources);
96507             layerList.call(updateLayerSelections);
96508
96509             function sortSources(a, b) {
96510               return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : d3_descending(a.area(), b.area()) || d3_ascending(a.name(), b.name()) || 0;
96511             }
96512           }
96513
96514           function renderDisclosureContent(selection) {
96515             var container = selection.selectAll('.layer-overlay-list').data([0]);
96516             _overlayList = container.enter().append('ul').attr('class', 'layer-list layer-overlay-list').attr('dir', 'auto').merge(container);
96517
96518             _overlayList.call(drawListItems, 'checkbox', chooseOverlay, function (d) {
96519               return !d.isHidden() && d.overlay;
96520             });
96521           }
96522
96523           context.map().on('move.overlay_list', debounce(function () {
96524             // layers in-view may have changed due to map move
96525             window.requestIdleCallback(section.reRender);
96526           }, 1000));
96527           return section;
96528         }
96529
96530         function uiPaneBackground(context) {
96531           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)]);
96532           return backgroundPane;
96533         }
96534
96535         function uiPaneHelp(context) {
96536           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']]];
96537           var headings = {
96538             'help.help.open_data_h': 3,
96539             'help.help.before_start_h': 3,
96540             'help.help.open_source_h': 3,
96541             'help.overview.navigation_h': 3,
96542             'help.overview.features_h': 3,
96543             'help.editing.select_h': 3,
96544             'help.editing.multiselect_h': 3,
96545             'help.editing.undo_redo_h': 3,
96546             'help.editing.save_h': 3,
96547             'help.editing.upload_h': 3,
96548             'help.editing.backups_h': 3,
96549             'help.editing.keyboard_h': 3,
96550             'help.feature_editor.type_h': 3,
96551             'help.feature_editor.fields_h': 3,
96552             'help.feature_editor.tags_h': 3,
96553             'help.points.add_point_h': 3,
96554             'help.points.move_point_h': 3,
96555             'help.points.delete_point_h': 3,
96556             'help.lines.add_line_h': 3,
96557             'help.lines.modify_line_h': 3,
96558             'help.lines.connect_line_h': 3,
96559             'help.lines.disconnect_line_h': 3,
96560             'help.lines.move_line_h': 3,
96561             'help.lines.delete_line_h': 3,
96562             'help.areas.point_or_area_h': 3,
96563             'help.areas.add_area_h': 3,
96564             'help.areas.square_area_h': 3,
96565             'help.areas.modify_area_h': 3,
96566             'help.areas.delete_area_h': 3,
96567             'help.relations.edit_relation_h': 3,
96568             'help.relations.maintain_relation_h': 3,
96569             'help.relations.relation_types_h': 2,
96570             'help.relations.multipolygon_h': 3,
96571             'help.relations.turn_restriction_h': 3,
96572             'help.relations.route_h': 3,
96573             'help.relations.boundary_h': 3,
96574             'help.notes.add_note_h': 3,
96575             'help.notes.update_note_h': 3,
96576             'help.notes.save_note_h': 3,
96577             'help.imagery.sources_h': 3,
96578             'help.imagery.offsets_h': 3,
96579             'help.streetlevel.using_h': 3,
96580             'help.gps.using_h': 3,
96581             'help.qa.tools_h': 3,
96582             'help.qa.issues_h': 3
96583           }; // For each section, squash all the texts into a single markdown document
96584
96585           var docs = docKeys.map(function (key) {
96586             var helpkey = 'help.' + key[0];
96587             var helpPaneReplacements = {
96588               version: context.version
96589             };
96590             var text = key[1].reduce(function (all, part) {
96591               var subkey = helpkey + '.' + part;
96592               var depth = headings[subkey]; // is this subkey a heading?
96593
96594               var hhh = depth ? Array(depth + 1).join('#') + ' ' : ''; // if so, prepend with some ##'s
96595
96596               return all + hhh + helpHtml(subkey, helpPaneReplacements) + '\n\n';
96597             }, '');
96598             return {
96599               title: _t.html(helpkey + '.title'),
96600               content: marked_1(text.trim()) // use keyboard key styling for shortcuts
96601               .replace(/<code>/g, '<kbd>').replace(/<\/code>/g, '<\/kbd>')
96602             };
96603           });
96604           var helpPane = uiPane('help', context).key(_t('help.key')).label(_t.html('help.title')).description(_t.html('help.title')).iconName('iD-icon-help');
96605
96606           helpPane.renderContent = function (content) {
96607             function clickHelp(d, i) {
96608               var rtl = _mainLocalizer.textDirection() === 'rtl';
96609               content.property('scrollTop', 0);
96610               helpPane.selection().select('.pane-heading h2').html(d.title);
96611               body.html(d.content);
96612               body.selectAll('a').attr('target', '_blank');
96613               menuItems.classed('selected', function (m) {
96614                 return m.title === d.title;
96615               });
96616               nav.html('');
96617
96618               if (rtl) {
96619                 nav.call(drawNext).call(drawPrevious);
96620               } else {
96621                 nav.call(drawPrevious).call(drawNext);
96622               }
96623
96624               function drawNext(selection) {
96625                 if (i < docs.length - 1) {
96626                   var nextLink = selection.append('a').attr('href', '#').attr('class', 'next').on('click', function (d3_event) {
96627                     d3_event.preventDefault();
96628                     clickHelp(docs[i + 1], i + 1);
96629                   });
96630                   nextLink.append('span').html(docs[i + 1].title).call(svgIcon(rtl ? '#iD-icon-backward' : '#iD-icon-forward', 'inline'));
96631                 }
96632               }
96633
96634               function drawPrevious(selection) {
96635                 if (i > 0) {
96636                   var prevLink = selection.append('a').attr('href', '#').attr('class', 'previous').on('click', function (d3_event) {
96637                     d3_event.preventDefault();
96638                     clickHelp(docs[i - 1], i - 1);
96639                   });
96640                   prevLink.call(svgIcon(rtl ? '#iD-icon-forward' : '#iD-icon-backward', 'inline')).append('span').html(docs[i - 1].title);
96641                 }
96642               }
96643             }
96644
96645             function clickWalkthrough(d3_event) {
96646               d3_event.preventDefault();
96647               if (context.inIntro()) return;
96648               context.container().call(uiIntro(context));
96649               context.ui().togglePanes();
96650             }
96651
96652             function clickShortcuts(d3_event) {
96653               d3_event.preventDefault();
96654               context.container().call(context.ui().shortcuts, true);
96655             }
96656
96657             var toc = content.append('ul').attr('class', 'toc');
96658             var menuItems = toc.selectAll('li').data(docs).enter().append('li').append('a').attr('href', '#').html(function (d) {
96659               return d.title;
96660             }).on('click', function (d3_event, d) {
96661               d3_event.preventDefault();
96662               clickHelp(d, docs.indexOf(d));
96663             });
96664             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);
96665             shortcuts.append('div').html(_t.html('shortcuts.title'));
96666             var walkthrough = toc.append('li').attr('class', 'walkthrough').append('a').attr('href', '#').on('click', clickWalkthrough);
96667             walkthrough.append('svg').attr('class', 'logo logo-walkthrough').append('use').attr('xlink:href', '#iD-logo-walkthrough');
96668             walkthrough.append('div').html(_t.html('splash.walkthrough'));
96669             var helpContent = content.append('div').attr('class', 'left-content');
96670             var body = helpContent.append('div').attr('class', 'body');
96671             var nav = helpContent.append('div').attr('class', 'nav');
96672             clickHelp(docs[0], 0);
96673           };
96674
96675           return helpPane;
96676         }
96677
96678         function uiSectionValidationIssues(id, severity, context) {
96679           var _issues = [];
96680           var section = uiSection(id, context).label(function () {
96681             if (!_issues) return '';
96682             var issueCountText = _issues.length > 1000 ? '1000+' : String(_issues.length);
96683             return _t('inspector.title_count', {
96684               title: _t.html('issues.' + severity + 's.list_title'),
96685               count: issueCountText
96686             });
96687           }).disclosureContent(renderDisclosureContent).shouldDisplay(function () {
96688             return _issues && _issues.length;
96689           });
96690
96691           function getOptions() {
96692             return {
96693               what: corePreferences('validate-what') || 'edited',
96694               where: corePreferences('validate-where') || 'all'
96695             };
96696           } // get and cache the issues to display, unordered
96697
96698
96699           function reloadIssues() {
96700             _issues = context.validator().getIssuesBySeverity(getOptions())[severity];
96701           }
96702
96703           function renderDisclosureContent(selection) {
96704             var center = context.map().center();
96705             var graph = context.graph(); // sort issues by distance away from the center of the map
96706
96707             var issues = _issues.map(function withDistance(issue) {
96708               var extent = issue.extent(graph);
96709               var dist = extent ? geoSphericalDistance(center, extent.center()) : 0;
96710               return Object.assign(issue, {
96711                 dist: dist
96712               });
96713             }).sort(function byDistance(a, b) {
96714               return a.dist - b.dist;
96715             }); // cut off at 1000
96716
96717
96718             issues = issues.slice(0, 1000); //renderIgnoredIssuesReset(_warningsSelection);
96719
96720             selection.call(drawIssuesList, issues);
96721           }
96722
96723           function drawIssuesList(selection, issues) {
96724             var list = selection.selectAll('.issues-list').data([0]);
96725             list = list.enter().append('ul').attr('class', 'layer-list issues-list ' + severity + 's-list').merge(list);
96726             var items = list.selectAll('li').data(issues, function (d) {
96727               return d.id;
96728             }); // Exit
96729
96730             items.exit().remove(); // Enter
96731
96732             var itemsEnter = items.enter().append('li').attr('class', function (d) {
96733               return 'issue severity-' + d.severity;
96734             });
96735             var labelsEnter = itemsEnter.append('button').attr('class', 'issue-label').on('click', function (d3_event, d) {
96736               context.validator().focusIssue(d);
96737             }).on('mouseover', function (d3_event, d) {
96738               utilHighlightEntities(d.entityIds, true, context);
96739             }).on('mouseout', function (d3_event, d) {
96740               utilHighlightEntities(d.entityIds, false, context);
96741             });
96742             var textEnter = labelsEnter.append('span').attr('class', 'issue-text');
96743             textEnter.append('span').attr('class', 'issue-icon').each(function (d) {
96744               var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
96745               select(this).call(svgIcon(iconName));
96746             });
96747             textEnter.append('span').attr('class', 'issue-message');
96748             /*
96749             labelsEnter
96750                 .append('span')
96751                 .attr('class', 'issue-autofix')
96752                 .each(function(d) {
96753                     if (!d.autoFix) return;
96754                      d3_select(this)
96755                         .append('button')
96756                         .attr('title', t('issues.fix_one.title'))
96757                         .datum(d.autoFix)  // set button datum to the autofix
96758                         .attr('class', 'autofix action')
96759                         .on('click', function(d3_event, d) {
96760                             d3_event.preventDefault();
96761                             d3_event.stopPropagation();
96762                              var issuesEntityIDs = d.issue.entityIds;
96763                             utilHighlightEntities(issuesEntityIDs.concat(d.entityIds), false, context);
96764                              context.perform.apply(context, d.autoArgs);
96765                             context.validator().validate();
96766                         })
96767                         .call(svgIcon('#iD-icon-wrench'));
96768                 });
96769             */
96770             // Update
96771
96772             items = items.merge(itemsEnter).order();
96773             items.selectAll('.issue-message').html(function (d) {
96774               return d.message(context);
96775             });
96776             /*
96777             // autofix
96778             var canAutoFix = issues.filter(function(issue) { return issue.autoFix; });
96779              var autoFixAll = selection.selectAll('.autofix-all')
96780                 .data(canAutoFix.length ? [0] : []);
96781              // exit
96782             autoFixAll.exit()
96783                 .remove();
96784              // enter
96785             var autoFixAllEnter = autoFixAll.enter()
96786                 .insert('div', '.issues-list')
96787                 .attr('class', 'autofix-all');
96788              var linkEnter = autoFixAllEnter
96789                 .append('a')
96790                 .attr('class', 'autofix-all-link')
96791                 .attr('href', '#');
96792              linkEnter
96793                 .append('span')
96794                 .attr('class', 'autofix-all-link-text')
96795                 .html(t.html('issues.fix_all.title'));
96796              linkEnter
96797                 .append('span')
96798                 .attr('class', 'autofix-all-link-icon')
96799                 .call(svgIcon('#iD-icon-wrench'));
96800              if (severity === 'warning') {
96801                 renderIgnoredIssuesReset(selection);
96802             }
96803              // update
96804             autoFixAll = autoFixAll
96805                 .merge(autoFixAllEnter);
96806              autoFixAll.selectAll('.autofix-all-link')
96807                 .on('click', function() {
96808                     context.pauseChangeDispatch();
96809                     context.perform(actionNoop());
96810                     canAutoFix.forEach(function(issue) {
96811                         var args = issue.autoFix.autoArgs.slice();  // copy
96812                         if (typeof args[args.length - 1] !== 'function') {
96813                             args.pop();
96814                         }
96815                         args.push(t('issues.fix_all.annotation'));
96816                         context.replace.apply(context, args);
96817                     });
96818                     context.resumeChangeDispatch();
96819                     context.validator().validate();
96820                 });
96821             */
96822           }
96823
96824           context.validator().on('validated.uiSectionValidationIssues' + id, function () {
96825             window.requestIdleCallback(function () {
96826               reloadIssues();
96827               section.reRender();
96828             });
96829           });
96830           context.map().on('move.uiSectionValidationIssues' + id, debounce(function () {
96831             window.requestIdleCallback(function () {
96832               if (getOptions().where === 'visible') {
96833                 // must refetch issues if they are viewport-dependent
96834                 reloadIssues();
96835               } // always reload list to re-sort-by-distance
96836
96837
96838               section.reRender();
96839             });
96840           }, 1000));
96841           return section;
96842         }
96843
96844         function uiSectionValidationOptions(context) {
96845           var section = uiSection('issues-options', context).content(renderContent);
96846
96847           function renderContent(selection) {
96848             var container = selection.selectAll('.issues-options-container').data([0]);
96849             container = container.enter().append('div').attr('class', 'issues-options-container').merge(container);
96850             var data = [{
96851               key: 'what',
96852               values: ['edited', 'all']
96853             }, {
96854               key: 'where',
96855               values: ['visible', 'all']
96856             }];
96857             var options = container.selectAll('.issues-option').data(data, function (d) {
96858               return d.key;
96859             });
96860             var optionsEnter = options.enter().append('div').attr('class', function (d) {
96861               return 'issues-option issues-option-' + d.key;
96862             });
96863             optionsEnter.append('div').attr('class', 'issues-option-title').html(function (d) {
96864               return _t.html('issues.options.' + d.key + '.title');
96865             });
96866             var valuesEnter = optionsEnter.selectAll('label').data(function (d) {
96867               return d.values.map(function (val) {
96868                 return {
96869                   value: val,
96870                   key: d.key
96871                 };
96872               });
96873             }).enter().append('label');
96874             valuesEnter.append('input').attr('type', 'radio').attr('name', function (d) {
96875               return 'issues-option-' + d.key;
96876             }).attr('value', function (d) {
96877               return d.value;
96878             }).property('checked', function (d) {
96879               return getOptions()[d.key] === d.value;
96880             }).on('change', function (d3_event, d) {
96881               updateOptionValue(d3_event, d.key, d.value);
96882             });
96883             valuesEnter.append('span').html(function (d) {
96884               return _t.html('issues.options.' + d.key + '.' + d.value);
96885             });
96886           }
96887
96888           function getOptions() {
96889             return {
96890               what: corePreferences('validate-what') || 'edited',
96891               // 'all', 'edited'
96892               where: corePreferences('validate-where') || 'all' // 'all', 'visible'
96893
96894             };
96895           }
96896
96897           function updateOptionValue(d3_event, d, val) {
96898             if (!val && d3_event && d3_event.target) {
96899               val = d3_event.target.value;
96900             }
96901
96902             corePreferences('validate-' + d, val);
96903             context.validator().validate();
96904           }
96905
96906           return section;
96907         }
96908
96909         function uiSectionValidationRules(context) {
96910           var MINSQUARE = 0;
96911           var MAXSQUARE = 20;
96912           var DEFAULTSQUARE = 5; // see also unsquare_way.js
96913
96914           var section = uiSection('issues-rules', context).disclosureContent(renderDisclosureContent).label(_t.html('issues.rules.title'));
96915
96916           var _ruleKeys = context.validator().getRuleKeys().filter(function (key) {
96917             return key !== 'maprules';
96918           }).sort(function (key1, key2) {
96919             // alphabetize by localized title
96920             return _t('issues.' + key1 + '.title') < _t('issues.' + key2 + '.title') ? -1 : 1;
96921           });
96922
96923           function renderDisclosureContent(selection) {
96924             var container = selection.selectAll('.issues-rulelist-container').data([0]);
96925             var containerEnter = container.enter().append('div').attr('class', 'issues-rulelist-container');
96926             containerEnter.append('ul').attr('class', 'layer-list issue-rules-list');
96927             var ruleLinks = containerEnter.append('div').attr('class', 'issue-rules-links section-footer');
96928             ruleLinks.append('a').attr('class', 'issue-rules-link').attr('href', '#').html(_t.html('issues.disable_all')).on('click', function (d3_event) {
96929               d3_event.preventDefault();
96930               context.validator().disableRules(_ruleKeys);
96931             });
96932             ruleLinks.append('a').attr('class', 'issue-rules-link').attr('href', '#').html(_t.html('issues.enable_all')).on('click', function (d3_event) {
96933               d3_event.preventDefault();
96934               context.validator().disableRules([]);
96935             }); // Update
96936
96937             container = container.merge(containerEnter);
96938             container.selectAll('.issue-rules-list').call(drawListItems, _ruleKeys, 'checkbox', 'rule', toggleRule, isRuleEnabled);
96939           }
96940
96941           function drawListItems(selection, data, type, name, change, active) {
96942             var items = selection.selectAll('li').data(data); // Exit
96943
96944             items.exit().remove(); // Enter
96945
96946             var enter = items.enter().append('li');
96947
96948             if (name === 'rule') {
96949               enter.call(uiTooltip().title(function (d) {
96950                 return _t.html('issues.' + d + '.tip');
96951               }).placement('top'));
96952             }
96953
96954             var label = enter.append('label');
96955             label.append('input').attr('type', type).attr('name', name).on('change', change);
96956             label.append('span').html(function (d) {
96957               var params = {};
96958
96959               if (d === 'unsquare_way') {
96960                 params.val = '<span class="square-degrees"></span>';
96961               }
96962
96963               return _t.html('issues.' + d + '.title', params);
96964             }); // Update
96965
96966             items = items.merge(enter);
96967             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', false); // user-configurable square threshold
96968
96969             var degStr = corePreferences('validate-square-degrees');
96970
96971             if (degStr === null) {
96972               degStr = DEFAULTSQUARE.toString();
96973             }
96974
96975             var span = items.selectAll('.square-degrees');
96976             var input = span.selectAll('.square-degrees-input').data([0]); // enter / update
96977
96978             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) {
96979               d3_event.preventDefault();
96980               d3_event.stopPropagation();
96981               this.select();
96982             }).on('keyup', function (d3_event) {
96983               if (d3_event.keyCode === 13) {
96984                 // ↩ Return
96985                 this.blur();
96986                 this.select();
96987               }
96988             }).on('blur', changeSquare).merge(input).property('value', degStr);
96989           }
96990
96991           function changeSquare() {
96992             var input = select(this);
96993             var degStr = utilGetSetValue(input).trim();
96994             var degNum = parseFloat(degStr, 10);
96995
96996             if (!isFinite(degNum)) {
96997               degNum = DEFAULTSQUARE;
96998             } else if (degNum > MAXSQUARE) {
96999               degNum = MAXSQUARE;
97000             } else if (degNum < MINSQUARE) {
97001               degNum = MINSQUARE;
97002             }
97003
97004             degNum = Math.round(degNum * 10) / 10; // round to 1 decimal
97005
97006             degStr = degNum.toString();
97007             input.property('value', degStr);
97008             corePreferences('validate-square-degrees', degStr);
97009             context.validator().reloadUnsquareIssues();
97010           }
97011
97012           function isRuleEnabled(d) {
97013             return context.validator().isRuleEnabled(d);
97014           }
97015
97016           function toggleRule(d3_event, d) {
97017             context.validator().toggleRule(d);
97018           }
97019
97020           context.validator().on('validated.uiSectionValidationRules', function () {
97021             window.requestIdleCallback(section.reRender);
97022           });
97023           return section;
97024         }
97025
97026         function uiSectionValidationStatus(context) {
97027           var section = uiSection('issues-status', context).content(renderContent).shouldDisplay(function () {
97028             var issues = context.validator().getIssues(getOptions());
97029             return issues.length === 0;
97030           });
97031
97032           function getOptions() {
97033             return {
97034               what: corePreferences('validate-what') || 'edited',
97035               where: corePreferences('validate-where') || 'all'
97036             };
97037           }
97038
97039           function renderContent(selection) {
97040             var box = selection.selectAll('.box').data([0]);
97041             var boxEnter = box.enter().append('div').attr('class', 'box');
97042             boxEnter.append('div').call(svgIcon('#iD-icon-apply', 'pre-text'));
97043             var noIssuesMessage = boxEnter.append('span');
97044             noIssuesMessage.append('strong').attr('class', 'message');
97045             noIssuesMessage.append('br');
97046             noIssuesMessage.append('span').attr('class', 'details');
97047             renderIgnoredIssuesReset(selection);
97048             setNoIssuesText(selection);
97049           }
97050
97051           function renderIgnoredIssuesReset(selection) {
97052             var ignoredIssues = context.validator().getIssues({
97053               what: 'all',
97054               where: 'all',
97055               includeDisabledRules: true,
97056               includeIgnored: 'only'
97057             });
97058             var resetIgnored = selection.selectAll('.reset-ignored').data(ignoredIssues.length ? [0] : []); // exit
97059
97060             resetIgnored.exit().remove(); // enter
97061
97062             var resetIgnoredEnter = resetIgnored.enter().append('div').attr('class', 'reset-ignored section-footer');
97063             resetIgnoredEnter.append('a').attr('href', '#'); // update
97064
97065             resetIgnored = resetIgnored.merge(resetIgnoredEnter);
97066             resetIgnored.select('a').html(_t('inspector.title_count', {
97067               title: _t.html('issues.reset_ignored'),
97068               count: ignoredIssues.length
97069             }));
97070             resetIgnored.on('click', function (d3_event) {
97071               d3_event.preventDefault();
97072               context.validator().resetIgnoredIssues();
97073             });
97074           }
97075
97076           function setNoIssuesText(selection) {
97077             var opts = getOptions();
97078
97079             function checkForHiddenIssues(cases) {
97080               for (var type in cases) {
97081                 var hiddenOpts = cases[type];
97082                 var hiddenIssues = context.validator().getIssues(hiddenOpts);
97083
97084                 if (hiddenIssues.length) {
97085                   selection.select('.box .details').html(_t.html('issues.no_issues.hidden_issues.' + type, {
97086                     count: hiddenIssues.length.toString()
97087                   }));
97088                   return;
97089                 }
97090               }
97091
97092               selection.select('.box .details').html(_t.html('issues.no_issues.hidden_issues.none'));
97093             }
97094
97095             var messageType;
97096
97097             if (opts.what === 'edited' && opts.where === 'visible') {
97098               messageType = 'edits_in_view';
97099               checkForHiddenIssues({
97100                 elsewhere: {
97101                   what: 'edited',
97102                   where: 'all'
97103                 },
97104                 everything_else: {
97105                   what: 'all',
97106                   where: 'visible'
97107                 },
97108                 disabled_rules: {
97109                   what: 'edited',
97110                   where: 'visible',
97111                   includeDisabledRules: 'only'
97112                 },
97113                 everything_else_elsewhere: {
97114                   what: 'all',
97115                   where: 'all'
97116                 },
97117                 disabled_rules_elsewhere: {
97118                   what: 'edited',
97119                   where: 'all',
97120                   includeDisabledRules: 'only'
97121                 },
97122                 ignored_issues: {
97123                   what: 'edited',
97124                   where: 'visible',
97125                   includeIgnored: 'only'
97126                 },
97127                 ignored_issues_elsewhere: {
97128                   what: 'edited',
97129                   where: 'all',
97130                   includeIgnored: 'only'
97131                 }
97132               });
97133             } else if (opts.what === 'edited' && opts.where === 'all') {
97134               messageType = 'edits';
97135               checkForHiddenIssues({
97136                 everything_else: {
97137                   what: 'all',
97138                   where: 'all'
97139                 },
97140                 disabled_rules: {
97141                   what: 'edited',
97142                   where: 'all',
97143                   includeDisabledRules: 'only'
97144                 },
97145                 ignored_issues: {
97146                   what: 'edited',
97147                   where: 'all',
97148                   includeIgnored: 'only'
97149                 }
97150               });
97151             } else if (opts.what === 'all' && opts.where === 'visible') {
97152               messageType = 'everything_in_view';
97153               checkForHiddenIssues({
97154                 elsewhere: {
97155                   what: 'all',
97156                   where: 'all'
97157                 },
97158                 disabled_rules: {
97159                   what: 'all',
97160                   where: 'visible',
97161                   includeDisabledRules: 'only'
97162                 },
97163                 disabled_rules_elsewhere: {
97164                   what: 'all',
97165                   where: 'all',
97166                   includeDisabledRules: 'only'
97167                 },
97168                 ignored_issues: {
97169                   what: 'all',
97170                   where: 'visible',
97171                   includeIgnored: 'only'
97172                 },
97173                 ignored_issues_elsewhere: {
97174                   what: 'all',
97175                   where: 'all',
97176                   includeIgnored: 'only'
97177                 }
97178               });
97179             } else if (opts.what === 'all' && opts.where === 'all') {
97180               messageType = 'everything';
97181               checkForHiddenIssues({
97182                 disabled_rules: {
97183                   what: 'all',
97184                   where: 'all',
97185                   includeDisabledRules: 'only'
97186                 },
97187                 ignored_issues: {
97188                   what: 'all',
97189                   where: 'all',
97190                   includeIgnored: 'only'
97191                 }
97192               });
97193             }
97194
97195             if (opts.what === 'edited' && context.history().difference().summary().length === 0) {
97196               messageType = 'no_edits';
97197             }
97198
97199             selection.select('.box .message').html(_t.html('issues.no_issues.message.' + messageType));
97200           }
97201
97202           context.validator().on('validated.uiSectionValidationStatus', function () {
97203             window.requestIdleCallback(section.reRender);
97204           });
97205           context.map().on('move.uiSectionValidationStatus', debounce(function () {
97206             window.requestIdleCallback(section.reRender);
97207           }, 1000));
97208           return section;
97209         }
97210
97211         function uiPaneIssues(context) {
97212           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)]);
97213           return issuesPane;
97214         }
97215
97216         function uiSettingsCustomData(context) {
97217           var dispatch$1 = dispatch('change');
97218
97219           function render(selection) {
97220             var dataLayer = context.layers().layer('data'); // keep separate copies of original and current settings
97221
97222             var _origSettings = {
97223               fileList: dataLayer && dataLayer.fileList() || null,
97224               url: corePreferences('settings-custom-data-url')
97225             };
97226             var _currSettings = {
97227               fileList: dataLayer && dataLayer.fileList() || null,
97228               url: corePreferences('settings-custom-data-url')
97229             }; // var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
97230
97231             var modal = uiConfirm(selection).okButton();
97232             modal.classed('settings-modal settings-custom-data', true);
97233             modal.select('.modal-section.header').append('h3').html(_t.html('settings.custom_data.header'));
97234             var textSection = modal.select('.modal-section.message-text');
97235             textSection.append('pre').attr('class', 'instructions-file').html(_t.html('settings.custom_data.file.instructions'));
97236             textSection.append('input').attr('class', 'field-file').attr('type', 'file').property('files', _currSettings.fileList) // works for all except IE11
97237             .on('change', function (d3_event) {
97238               var files = d3_event.target.files;
97239
97240               if (files && files.length) {
97241                 _currSettings.url = '';
97242                 textSection.select('.field-url').property('value', '');
97243                 _currSettings.fileList = files;
97244               } else {
97245                 _currSettings.fileList = null;
97246               }
97247             });
97248             textSection.append('h4').html(_t.html('settings.custom_data.or'));
97249             textSection.append('pre').attr('class', 'instructions-url').html(_t.html('settings.custom_data.url.instructions'));
97250             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
97251
97252             var buttonSection = modal.select('.modal-section.buttons');
97253             buttonSection.insert('button', '.ok-button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
97254             buttonSection.select('.cancel-button').on('click.cancel', clickCancel);
97255             buttonSection.select('.ok-button').attr('disabled', isSaveDisabled).on('click.save', clickSave);
97256
97257             function isSaveDisabled() {
97258               return null;
97259             } // restore the original url
97260
97261
97262             function clickCancel() {
97263               textSection.select('.field-url').property('value', _origSettings.url);
97264               corePreferences('settings-custom-data-url', _origSettings.url);
97265               this.blur();
97266               modal.close();
97267             } // accept the current url
97268
97269
97270             function clickSave() {
97271               _currSettings.url = textSection.select('.field-url').property('value').trim(); // one or the other but not both
97272
97273               if (_currSettings.url) {
97274                 _currSettings.fileList = null;
97275               }
97276
97277               if (_currSettings.fileList) {
97278                 _currSettings.url = '';
97279               }
97280
97281               corePreferences('settings-custom-data-url', _currSettings.url);
97282               this.blur();
97283               modal.close();
97284               dispatch$1.call('change', this, _currSettings);
97285             }
97286           }
97287
97288           return utilRebind(render, dispatch$1, 'on');
97289         }
97290
97291         function uiSectionDataLayers(context) {
97292           var settingsCustomData = uiSettingsCustomData(context).on('change', customChanged);
97293           var layers = context.layers();
97294           var section = uiSection('data-layers', context).label(_t.html('map_data.data_layers')).disclosureContent(renderDisclosureContent);
97295
97296           function renderDisclosureContent(selection) {
97297             var container = selection.selectAll('.data-layer-container').data([0]);
97298             container.enter().append('div').attr('class', 'data-layer-container').merge(container).call(drawOsmItems).call(drawQAItems).call(drawCustomDataItems).call(drawVectorItems) // Beta - Detroit mapping challenge
97299             .call(drawPanelItems);
97300           }
97301
97302           function showsLayer(which) {
97303             var layer = layers.layer(which);
97304
97305             if (layer) {
97306               return layer.enabled();
97307             }
97308
97309             return false;
97310           }
97311
97312           function setLayer(which, enabled) {
97313             // Don't allow layer changes while drawing - #6584
97314             var mode = context.mode();
97315             if (mode && /^draw/.test(mode.id)) return;
97316             var layer = layers.layer(which);
97317
97318             if (layer) {
97319               layer.enabled(enabled);
97320
97321               if (!enabled && (which === 'osm' || which === 'notes')) {
97322                 context.enter(modeBrowse(context));
97323               }
97324             }
97325           }
97326
97327           function toggleLayer(which) {
97328             setLayer(which, !showsLayer(which));
97329           }
97330
97331           function drawOsmItems(selection) {
97332             var osmKeys = ['osm', 'notes'];
97333             var osmLayers = layers.all().filter(function (obj) {
97334               return osmKeys.indexOf(obj.id) !== -1;
97335             });
97336             var ul = selection.selectAll('.layer-list-osm').data([0]);
97337             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-osm').merge(ul);
97338             var li = ul.selectAll('.list-item').data(osmLayers);
97339             li.exit().remove();
97340             var liEnter = li.enter().append('li').attr('class', function (d) {
97341               return 'list-item list-item-' + d.id;
97342             });
97343             var labelEnter = liEnter.append('label').each(function (d) {
97344               if (d.id === 'osm') {
97345                 select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).keys([uiCmd('⌥' + _t('area_fill.wireframe.key'))]).placement('bottom'));
97346               } else {
97347                 select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).placement('bottom'));
97348               }
97349             });
97350             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
97351               toggleLayer(d.id);
97352             });
97353             labelEnter.append('span').html(function (d) {
97354               return _t.html('map_data.layers.' + d.id + '.title');
97355             }); // Update
97356
97357             li.merge(liEnter).classed('active', function (d) {
97358               return d.layer.enabled();
97359             }).selectAll('input').property('checked', function (d) {
97360               return d.layer.enabled();
97361             });
97362           }
97363
97364           function drawQAItems(selection) {
97365             var qaKeys = ['keepRight', 'improveOSM', 'osmose'];
97366             var qaLayers = layers.all().filter(function (obj) {
97367               return qaKeys.indexOf(obj.id) !== -1;
97368             });
97369             var ul = selection.selectAll('.layer-list-qa').data([0]);
97370             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-qa').merge(ul);
97371             var li = ul.selectAll('.list-item').data(qaLayers);
97372             li.exit().remove();
97373             var liEnter = li.enter().append('li').attr('class', function (d) {
97374               return 'list-item list-item-' + d.id;
97375             });
97376             var labelEnter = liEnter.append('label').each(function (d) {
97377               select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).placement('bottom'));
97378             });
97379             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
97380               toggleLayer(d.id);
97381             });
97382             labelEnter.append('span').html(function (d) {
97383               return _t.html('map_data.layers.' + d.id + '.title');
97384             }); // Update
97385
97386             li.merge(liEnter).classed('active', function (d) {
97387               return d.layer.enabled();
97388             }).selectAll('input').property('checked', function (d) {
97389               return d.layer.enabled();
97390             });
97391           } // Beta feature - sample vector layers to support Detroit Mapping Challenge
97392           // https://github.com/osmus/detroit-mapping-challenge
97393
97394
97395           function drawVectorItems(selection) {
97396             var dataLayer = layers.layer('data');
97397             var vtData = [{
97398               name: 'Detroit Neighborhoods/Parks',
97399               src: 'neighborhoods-parks',
97400               tooltip: 'Neighborhood boundaries and parks as compiled by City of Detroit in concert with community groups.',
97401               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'
97402             }, {
97403               name: 'Detroit Composite POIs',
97404               src: 'composite-poi',
97405               tooltip: 'Fire Inspections, Business Licenses, and other public location data collated from the City of Detroit.',
97406               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'
97407             }, {
97408               name: 'Detroit All-The-Places POIs',
97409               src: 'alltheplaces-poi',
97410               tooltip: 'Public domain business location data created by web scrapers.',
97411               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'
97412             }]; // Only show this if the map is around Detroit..
97413
97414             var detroit = geoExtent([-83.5, 42.1], [-82.8, 42.5]);
97415             var showVectorItems = context.map().zoom() > 9 && detroit.contains(context.map().center());
97416             var container = selection.selectAll('.vectortile-container').data(showVectorItems ? [0] : []);
97417             container.exit().remove();
97418             var containerEnter = container.enter().append('div').attr('class', 'vectortile-container');
97419             containerEnter.append('h4').attr('class', 'vectortile-header').html('Detroit Vector Tiles (Beta)');
97420             containerEnter.append('ul').attr('class', 'layer-list layer-list-vectortile');
97421             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');
97422             container = container.merge(containerEnter);
97423             var ul = container.selectAll('.layer-list-vectortile');
97424             var li = ul.selectAll('.list-item').data(vtData);
97425             li.exit().remove();
97426             var liEnter = li.enter().append('li').attr('class', function (d) {
97427               return 'list-item list-item-' + d.src;
97428             });
97429             var labelEnter = liEnter.append('label').each(function (d) {
97430               select(this).call(uiTooltip().title(d.tooltip).placement('top'));
97431             });
97432             labelEnter.append('input').attr('type', 'radio').attr('name', 'vectortile').on('change', selectVTLayer);
97433             labelEnter.append('span').html(function (d) {
97434               return d.name;
97435             }); // Update
97436
97437             li.merge(liEnter).classed('active', isVTLayerSelected).selectAll('input').property('checked', isVTLayerSelected);
97438
97439             function isVTLayerSelected(d) {
97440               return dataLayer && dataLayer.template() === d.template;
97441             }
97442
97443             function selectVTLayer(d3_event, d) {
97444               corePreferences('settings-custom-data-url', d.template);
97445
97446               if (dataLayer) {
97447                 dataLayer.template(d.template, d.src);
97448                 dataLayer.enabled(true);
97449               }
97450             }
97451           }
97452
97453           function drawCustomDataItems(selection) {
97454             var dataLayer = layers.layer('data');
97455             var hasData = dataLayer && dataLayer.hasData();
97456             var showsData = hasData && dataLayer.enabled();
97457             var ul = selection.selectAll('.layer-list-data').data(dataLayer ? [0] : []); // Exit
97458
97459             ul.exit().remove(); // Enter
97460
97461             var ulEnter = ul.enter().append('ul').attr('class', 'layer-list layer-list-data');
97462             var liEnter = ulEnter.append('li').attr('class', 'list-item-data');
97463             var labelEnter = liEnter.append('label').call(uiTooltip().title(_t.html('map_data.layers.custom.tooltip')).placement('top'));
97464             labelEnter.append('input').attr('type', 'checkbox').on('change', function () {
97465               toggleLayer('data');
97466             });
97467             labelEnter.append('span').html(_t.html('map_data.layers.custom.title'));
97468             liEnter.append('button').attr('class', 'open-data-options').call(uiTooltip().title(_t.html('settings.custom_data.tooltip')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).on('click', function (d3_event) {
97469               d3_event.preventDefault();
97470               editCustom();
97471             }).call(svgIcon('#iD-icon-more'));
97472             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) {
97473               if (select(this).classed('disabled')) return;
97474               d3_event.preventDefault();
97475               d3_event.stopPropagation();
97476               dataLayer.fitZoom();
97477             }).call(svgIcon('#iD-icon-framed-dot', 'monochrome')); // Update
97478
97479             ul = ul.merge(ulEnter);
97480             ul.selectAll('.list-item-data').classed('active', showsData).selectAll('label').classed('deemphasize', !hasData).selectAll('input').property('disabled', !hasData).property('checked', showsData);
97481             ul.selectAll('button.zoom-to-data').classed('disabled', !hasData);
97482           }
97483
97484           function editCustom() {
97485             context.container().call(settingsCustomData);
97486           }
97487
97488           function customChanged(d) {
97489             var dataLayer = layers.layer('data');
97490
97491             if (d && d.url) {
97492               dataLayer.url(d.url);
97493             } else if (d && d.fileList) {
97494               dataLayer.fileList(d.fileList);
97495             }
97496           }
97497
97498           function drawPanelItems(selection) {
97499             var panelsListEnter = selection.selectAll('.md-extras-list').data([0]).enter().append('ul').attr('class', 'layer-list md-extras-list');
97500             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'));
97501             historyPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
97502               d3_event.preventDefault();
97503               context.ui().info.toggle('history');
97504             });
97505             historyPanelLabelEnter.append('span').html(_t.html('map_data.history_panel.title'));
97506             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'));
97507             measurementPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
97508               d3_event.preventDefault();
97509               context.ui().info.toggle('measurement');
97510             });
97511             measurementPanelLabelEnter.append('span').html(_t.html('map_data.measurement_panel.title'));
97512           }
97513
97514           context.layers().on('change.uiSectionDataLayers', section.reRender);
97515           context.map().on('move.uiSectionDataLayers', debounce(function () {
97516             // Detroit layers may have moved in or out of view
97517             window.requestIdleCallback(section.reRender);
97518           }, 1000));
97519           return section;
97520         }
97521
97522         function uiSectionMapFeatures(context) {
97523           var _features = context.features().keys();
97524
97525           var section = uiSection('map-features', context).label(_t.html('map_data.map_features')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
97526
97527           function renderDisclosureContent(selection) {
97528             var container = selection.selectAll('.layer-feature-list-container').data([0]);
97529             var containerEnter = container.enter().append('div').attr('class', 'layer-feature-list-container');
97530             containerEnter.append('ul').attr('class', 'layer-list layer-feature-list');
97531             var footer = containerEnter.append('div').attr('class', 'feature-list-links section-footer');
97532             footer.append('a').attr('class', 'feature-list-link').attr('href', '#').html(_t.html('issues.disable_all')).on('click', function (d3_event) {
97533               d3_event.preventDefault();
97534               context.features().disableAll();
97535             });
97536             footer.append('a').attr('class', 'feature-list-link').attr('href', '#').html(_t.html('issues.enable_all')).on('click', function (d3_event) {
97537               d3_event.preventDefault();
97538               context.features().enableAll();
97539             }); // Update
97540
97541             container = container.merge(containerEnter);
97542             container.selectAll('.layer-feature-list').call(drawListItems, _features, 'checkbox', 'feature', clickFeature, showsFeature);
97543           }
97544
97545           function drawListItems(selection, data, type, name, change, active) {
97546             var items = selection.selectAll('li').data(data); // Exit
97547
97548             items.exit().remove(); // Enter
97549
97550             var enter = items.enter().append('li').call(uiTooltip().title(function (d) {
97551               var tip = _t.html(name + '.' + d + '.tooltip');
97552
97553               if (autoHiddenFeature(d)) {
97554                 var msg = showsLayer('osm') ? _t.html('map_data.autohidden') : _t.html('map_data.osmhidden');
97555                 tip += '<div>' + msg + '</div>';
97556               }
97557
97558               return tip;
97559             }).placement('top'));
97560             var label = enter.append('label');
97561             label.append('input').attr('type', type).attr('name', name).on('change', change);
97562             label.append('span').html(function (d) {
97563               return _t.html(name + '.' + d + '.description');
97564             }); // Update
97565
97566             items = items.merge(enter);
97567             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', autoHiddenFeature);
97568           }
97569
97570           function autoHiddenFeature(d) {
97571             return context.features().autoHidden(d);
97572           }
97573
97574           function showsFeature(d) {
97575             return context.features().enabled(d);
97576           }
97577
97578           function clickFeature(d3_event, d) {
97579             context.features().toggle(d);
97580           }
97581
97582           function showsLayer(id) {
97583             var layer = context.layers().layer(id);
97584             return layer && layer.enabled();
97585           } // add listeners
97586
97587
97588           context.features().on('change.map_features', section.reRender);
97589           return section;
97590         }
97591
97592         function uiSectionMapStyleOptions(context) {
97593           var section = uiSection('fill-area', context).label(_t.html('map_data.style_options')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
97594
97595           function renderDisclosureContent(selection) {
97596             var container = selection.selectAll('.layer-fill-list').data([0]);
97597             container.enter().append('ul').attr('class', 'layer-list layer-fill-list').merge(container).call(drawListItems, context.map().areaFillOptions, 'radio', 'area_fill', setFill, isActiveFill);
97598             var container2 = selection.selectAll('.layer-visual-diff-list').data([0]);
97599             container2.enter().append('ul').attr('class', 'layer-list layer-visual-diff-list').merge(container2).call(drawListItems, ['highlight_edits'], 'checkbox', 'visual_diff', toggleHighlightEdited, function () {
97600               return context.surface().classed('highlight-edited');
97601             });
97602           }
97603
97604           function drawListItems(selection, data, type, name, change, active) {
97605             var items = selection.selectAll('li').data(data); // Exit
97606
97607             items.exit().remove(); // Enter
97608
97609             var enter = items.enter().append('li').call(uiTooltip().title(function (d) {
97610               return _t.html(name + '.' + d + '.tooltip');
97611             }).keys(function (d) {
97612               var key = d === 'wireframe' ? _t('area_fill.wireframe.key') : null;
97613               if (d === 'highlight_edits') key = _t('map_data.highlight_edits.key');
97614               return key ? [key] : null;
97615             }).placement('top'));
97616             var label = enter.append('label');
97617             label.append('input').attr('type', type).attr('name', name).on('change', change);
97618             label.append('span').html(function (d) {
97619               return _t.html(name + '.' + d + '.description');
97620             }); // Update
97621
97622             items = items.merge(enter);
97623             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', false);
97624           }
97625
97626           function isActiveFill(d) {
97627             return context.map().activeAreaFill() === d;
97628           }
97629
97630           function toggleHighlightEdited(d3_event) {
97631             d3_event.preventDefault();
97632             context.map().toggleHighlightEdited();
97633           }
97634
97635           function setFill(d3_event, d) {
97636             context.map().activeAreaFill(d);
97637           }
97638
97639           context.map().on('changeHighlighting.ui_style, changeAreaFill.ui_style', section.reRender);
97640           return section;
97641         }
97642
97643         function uiSectionPhotoOverlays(context) {
97644           var layers = context.layers();
97645           var section = uiSection('photo-overlays', context).label(_t.html('photo_overlays.title')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
97646
97647           function renderDisclosureContent(selection) {
97648             var container = selection.selectAll('.photo-overlay-container').data([0]);
97649             container.enter().append('div').attr('class', 'photo-overlay-container').merge(container).call(drawPhotoItems).call(drawPhotoTypeItems).call(drawDateFilter).call(drawUsernameFilter);
97650           }
97651
97652           function drawPhotoItems(selection) {
97653             var photoKeys = context.photos().overlayLayerIDs();
97654             var photoLayers = layers.all().filter(function (obj) {
97655               return photoKeys.indexOf(obj.id) !== -1;
97656             });
97657             var data = photoLayers.filter(function (obj) {
97658               return obj.layer.supported();
97659             });
97660
97661             function layerSupported(d) {
97662               return d.layer && d.layer.supported();
97663             }
97664
97665             function layerEnabled(d) {
97666               return layerSupported(d) && d.layer.enabled();
97667             }
97668
97669             var ul = selection.selectAll('.layer-list-photos').data([0]);
97670             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-photos').merge(ul);
97671             var li = ul.selectAll('.list-item-photos').data(data);
97672             li.exit().remove();
97673             var liEnter = li.enter().append('li').attr('class', function (d) {
97674               var classes = 'list-item-photos list-item-' + d.id;
97675
97676               if (d.id === 'mapillary-signs' || d.id === 'mapillary-map-features') {
97677                 classes += ' indented';
97678               }
97679
97680               return classes;
97681             });
97682             var labelEnter = liEnter.append('label').each(function (d) {
97683               var titleID;
97684               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';
97685               select(this).call(uiTooltip().title(_t.html(titleID)).placement('top'));
97686             });
97687             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
97688               toggleLayer(d.id);
97689             });
97690             labelEnter.append('span').html(function (d) {
97691               var id = d.id;
97692               if (id === 'mapillary-signs') id = 'photo_overlays.traffic_signs';
97693               return _t.html(id.replace(/-/g, '_') + '.title');
97694             }); // Update
97695
97696             li.merge(liEnter).classed('active', layerEnabled).selectAll('input').property('checked', layerEnabled);
97697           }
97698
97699           function drawPhotoTypeItems(selection) {
97700             var data = context.photos().allPhotoTypes();
97701
97702             function typeEnabled(d) {
97703               return context.photos().showsPhotoType(d);
97704             }
97705
97706             var ul = selection.selectAll('.layer-list-photo-types').data([0]);
97707             ul.exit().remove();
97708             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-photo-types').merge(ul);
97709             var li = ul.selectAll('.list-item-photo-types').data(context.photos().shouldFilterByPhotoType() ? data : []);
97710             li.exit().remove();
97711             var liEnter = li.enter().append('li').attr('class', function (d) {
97712               return 'list-item-photo-types list-item-' + d;
97713             });
97714             var labelEnter = liEnter.append('label').each(function (d) {
97715               select(this).call(uiTooltip().title(_t.html('photo_overlays.photo_type.' + d + '.tooltip')).placement('top'));
97716             });
97717             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
97718               context.photos().togglePhotoType(d);
97719             });
97720             labelEnter.append('span').html(function (d) {
97721               return _t.html('photo_overlays.photo_type.' + d + '.title');
97722             }); // Update
97723
97724             li.merge(liEnter).classed('active', typeEnabled).selectAll('input').property('checked', typeEnabled);
97725           }
97726
97727           function drawDateFilter(selection) {
97728             var data = context.photos().dateFilters();
97729
97730             function filterEnabled(d) {
97731               return context.photos().dateFilterValue(d);
97732             }
97733
97734             var ul = selection.selectAll('.layer-list-date-filter').data([0]);
97735             ul.exit().remove();
97736             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-date-filter').merge(ul);
97737             var li = ul.selectAll('.list-item-date-filter').data(context.photos().shouldFilterByDate() ? data : []);
97738             li.exit().remove();
97739             var liEnter = li.enter().append('li').attr('class', 'list-item-date-filter');
97740             var labelEnter = liEnter.append('label').each(function (d) {
97741               select(this).call(uiTooltip().title(_t.html('photo_overlays.date_filter.' + d + '.tooltip')).placement('top'));
97742             });
97743             labelEnter.append('span').html(function (d) {
97744               return _t.html('photo_overlays.date_filter.' + d + '.title');
97745             });
97746             labelEnter.append('input').attr('type', 'date').attr('class', 'list-item-input').attr('placeholder', _t('units.year_month_day')).call(utilNoAuto).each(function (d) {
97747               utilGetSetValue(select(this), context.photos().dateFilterValue(d) || '');
97748             }).on('change', function (d3_event, d) {
97749               var value = utilGetSetValue(select(this)).trim();
97750               context.photos().setDateFilter(d, value, true); // reload the displayed dates
97751
97752               li.selectAll('input').each(function (d) {
97753                 utilGetSetValue(select(this), context.photos().dateFilterValue(d) || '');
97754               });
97755             });
97756             li = li.merge(liEnter).classed('active', filterEnabled);
97757           }
97758
97759           function drawUsernameFilter(selection) {
97760             function filterEnabled() {
97761               return context.photos().usernames();
97762             }
97763
97764             var ul = selection.selectAll('.layer-list-username-filter').data([0]);
97765             ul.exit().remove();
97766             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-username-filter').merge(ul);
97767             var li = ul.selectAll('.list-item-username-filter').data(context.photos().shouldFilterByUsername() ? ['username-filter'] : []);
97768             li.exit().remove();
97769             var liEnter = li.enter().append('li').attr('class', 'list-item-username-filter');
97770             var labelEnter = liEnter.append('label').each(function () {
97771               select(this).call(uiTooltip().title(_t.html('photo_overlays.username_filter.tooltip')).placement('top'));
97772             });
97773             labelEnter.append('span').html(_t.html('photo_overlays.username_filter.title'));
97774             labelEnter.append('input').attr('type', 'text').attr('class', 'list-item-input').call(utilNoAuto).property('value', usernameValue).on('change', function () {
97775               var value = select(this).property('value');
97776               context.photos().setUsernameFilter(value, true);
97777               select(this).property('value', usernameValue);
97778             });
97779             li.merge(liEnter).classed('active', filterEnabled);
97780
97781             function usernameValue() {
97782               var usernames = context.photos().usernames();
97783               if (usernames) return usernames.join('; ');
97784               return usernames;
97785             }
97786           }
97787
97788           function toggleLayer(which) {
97789             setLayer(which, !showsLayer(which));
97790           }
97791
97792           function showsLayer(which) {
97793             var layer = layers.layer(which);
97794
97795             if (layer) {
97796               return layer.enabled();
97797             }
97798
97799             return false;
97800           }
97801
97802           function setLayer(which, enabled) {
97803             var layer = layers.layer(which);
97804
97805             if (layer) {
97806               layer.enabled(enabled);
97807             }
97808           }
97809
97810           context.layers().on('change.uiSectionPhotoOverlays', section.reRender);
97811           context.photos().on('change.uiSectionPhotoOverlays', section.reRender);
97812           return section;
97813         }
97814
97815         function uiPaneMapData(context) {
97816           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)]);
97817           return mapDataPane;
97818         }
97819
97820         function uiSectionPrivacy(context) {
97821           var section = uiSection('preferences-third-party', context).label(_t.html('preferences.privacy.title')).disclosureContent(renderDisclosureContent);
97822
97823           var _showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
97824
97825           function renderDisclosureContent(selection) {
97826             // enter
97827             var privacyOptionsListEnter = selection.selectAll('.privacy-options-list').data([0]).enter().append('ul').attr('class', 'layer-list privacy-options-list');
97828             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'));
97829             thirdPartyIconsEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
97830               d3_event.preventDefault();
97831               _showThirdPartyIcons = _showThirdPartyIcons === 'true' ? 'false' : 'true';
97832               corePreferences('preferences.privacy.thirdpartyicons', _showThirdPartyIcons);
97833               update();
97834             });
97835             thirdPartyIconsEnter.append('span').html(_t.html('preferences.privacy.third_party_icons.description')); // Privacy Policy link
97836
97837             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'));
97838             update();
97839
97840             function update() {
97841               selection.selectAll('.privacy-third-party-icons-item').classed('active', _showThirdPartyIcons === 'true').select('input').property('checked', _showThirdPartyIcons === 'true');
97842             }
97843           }
97844
97845           return section;
97846         }
97847
97848         function uiPanePreferences(context) {
97849           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)]);
97850           return preferencesPane;
97851         }
97852
97853         function uiInit(context) {
97854           var _initCounter = 0;
97855           var _needWidth = {};
97856
97857           var _lastPointerType;
97858
97859           function render(container) {
97860             container.on('click.ui', function (d3_event) {
97861               // we're only concerned with the primary mouse button
97862               if (d3_event.button !== 0) return;
97863               if (!d3_event.composedPath) return; // some targets have default click events we don't want to override
97864
97865               var isOkayTarget = d3_event.composedPath().some(function (node) {
97866                 // we only care about element nodes
97867                 return node.nodeType === 1 && ( // clicking <input> focuses it and/or changes a value
97868                 node.nodeName === 'INPUT' || // clicking <label> affects its <input> by default
97869                 node.nodeName === 'LABEL' || // clicking <a> opens a hyperlink by default
97870                 node.nodeName === 'A');
97871               });
97872               if (isOkayTarget) return; // disable double-tap-to-zoom on touchscreens
97873
97874               d3_event.preventDefault();
97875             });
97876             var detected = utilDetect(); // only WebKit supports gesture events
97877
97878             if ('GestureEvent' in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
97879             // but we only need to do this on desktop Safari anyway. – #7694
97880             !detected.isMobileWebKit) {
97881               // On iOS we disable pinch-to-zoom of the UI via the `touch-action`
97882               // CSS property, but on desktop Safari we need to manually cancel the
97883               // default gesture events.
97884               container.on('gesturestart.ui gesturechange.ui gestureend.ui', function (d3_event) {
97885                 // disable pinch-to-zoom of the UI via multitouch trackpads on macOS Safari
97886                 d3_event.preventDefault();
97887               });
97888             }
97889
97890             if ('PointerEvent' in window) {
97891               select(window).on('pointerdown.ui pointerup.ui', function (d3_event) {
97892                 var pointerType = d3_event.pointerType || 'mouse';
97893
97894                 if (_lastPointerType !== pointerType) {
97895                   _lastPointerType = pointerType;
97896                   container.attr('pointer', pointerType);
97897                 }
97898               }, true);
97899             } else {
97900               _lastPointerType = 'mouse';
97901               container.attr('pointer', 'mouse');
97902             }
97903
97904             container.attr('lang', _mainLocalizer.localeCode()).attr('dir', _mainLocalizer.textDirection()); // setup fullscreen keybindings (no button shown at this time)
97905
97906             container.call(uiFullScreen(context));
97907             var map = context.map();
97908             map.redrawEnable(false); // don't draw until we've set zoom/lat/long
97909
97910             map.on('hitMinZoom.ui', function () {
97911               ui.flash.iconName('#iD-icon-no').label(_t.html('cannot_zoom'))();
97912             });
97913             container.append('svg').attr('id', 'ideditor-defs').call(ui.svgDefs);
97914             container.append('div').attr('class', 'sidebar').call(ui.sidebar);
97915             var content = container.append('div').attr('class', 'main-content active'); // Top toolbar
97916
97917             content.append('div').attr('class', 'top-toolbar-wrap').append('div').attr('class', 'top-toolbar fillD').call(uiTopToolbar(context));
97918             content.append('div').attr('class', 'main-map').attr('dir', 'ltr').call(map);
97919             var overMap = content.append('div').attr('class', 'over-map'); // HACK: Mobile Safari 14 likes to select anything selectable when long-
97920             // pressing, even if it's not targeted. This conflicts with long-pressing
97921             // to show the edit menu. We add a selectable offscreen element as the first
97922             // child to trick Safari into not showing the selection UI.
97923
97924             overMap.append('div').attr('class', 'select-trap').text('t');
97925             overMap.call(uiMapInMap(context)).call(uiNotice(context));
97926             overMap.append('div').attr('class', 'spinner').call(uiSpinner(context)); // Map controls
97927
97928             var controls = overMap.append('div').attr('class', 'map-controls');
97929             controls.append('div').attr('class', 'map-control zoombuttons').call(uiZoom(context));
97930             controls.append('div').attr('class', 'map-control zoom-to-selection-control').call(uiZoomToSelection(context));
97931             controls.append('div').attr('class', 'map-control geolocate-control').call(uiGeolocate(context)); // Add panes
97932             // This should happen after map is initialized, as some require surface()
97933
97934             var panes = overMap.append('div').attr('class', 'map-panes');
97935             var uiPanes = [uiPaneBackground(context), uiPaneMapData(context), uiPaneIssues(context), uiPanePreferences(context), uiPaneHelp(context)];
97936             uiPanes.forEach(function (pane) {
97937               controls.append('div').attr('class', 'map-control map-pane-control ' + pane.id + '-control').call(pane.renderToggleButton);
97938               panes.call(pane.renderPane);
97939             });
97940             ui.info = uiInfo(context);
97941             overMap.call(ui.info);
97942             overMap.append('div').attr('class', 'photoviewer').classed('al', true) // 'al'=left,  'ar'=right
97943             .classed('hide', true).call(ui.photoviewer);
97944             overMap.append('div').attr('class', 'attribution-wrap').attr('dir', 'ltr').call(uiAttribution(context)); // Add footer
97945
97946             var about = content.append('div').attr('class', 'map-footer');
97947             about.append('div').attr('class', 'api-status').call(uiStatus(context));
97948             var footer = about.append('div').attr('class', 'map-footer-bar fillD');
97949             footer.append('div').attr('class', 'flash-wrap footer-hide');
97950             var footerWrap = footer.append('div').attr('class', 'main-footer-wrap footer-show');
97951             footerWrap.append('div').attr('class', 'scale-block').call(uiScale(context));
97952             var aboutList = footerWrap.append('div').attr('class', 'info-block').append('ul').attr('class', 'map-footer-list');
97953             aboutList.append('li').attr('class', 'user-list').call(uiContributors(context));
97954             var apiConnections = context.apiConnections();
97955
97956             if (apiConnections && apiConnections.length > 1) {
97957               aboutList.append('li').attr('class', 'source-switch').call(uiSourceSwitch(context).keys(apiConnections));
97958             }
97959
97960             aboutList.append('li').attr('class', 'issues-info').call(uiIssuesInfo(context));
97961             aboutList.append('li').attr('class', 'feature-warning').call(uiFeatureInfo(context));
97962             var issueLinks = aboutList.append('li');
97963             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'));
97964             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'));
97965             aboutList.append('li').attr('class', 'version').call(uiVersion(context));
97966
97967             if (!context.embed()) {
97968               aboutList.call(uiAccount(context));
97969             } // Setup map dimensions and move map to initial center/zoom.
97970             // This should happen after .main-content and toolbars exist.
97971
97972
97973             ui.onResize();
97974             map.redrawEnable(true);
97975             ui.hash = behaviorHash(context);
97976             ui.hash();
97977
97978             if (!ui.hash.hadHash) {
97979               map.centerZoom([0, 0], 2);
97980             } // Bind events
97981
97982
97983             window.onbeforeunload = function () {
97984               return context.save();
97985             };
97986
97987             window.onunload = function () {
97988               context.history().unlock();
97989             };
97990
97991             select(window).on('resize.editor', function () {
97992               ui.onResize();
97993             });
97994             var panPixels = 80;
97995             context.keybinding().on('⌫', function (d3_event) {
97996               d3_event.preventDefault();
97997             }).on([_t('sidebar.key'), '`', '²', '@'], ui.sidebar.toggle) // #5663, #6864 - common QWERTY, AZERTY
97998             .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) {
97999               if (d3_event) {
98000                 d3_event.stopImmediatePropagation();
98001                 d3_event.preventDefault();
98002               }
98003
98004               var previousBackground = context.background().findSource(corePreferences('background-last-used-toggle'));
98005
98006               if (previousBackground) {
98007                 var currentBackground = context.background().baseLayerSource();
98008                 corePreferences('background-last-used-toggle', currentBackground.id);
98009                 corePreferences('background-last-used', previousBackground.id);
98010                 context.background().baseLayerSource(previousBackground);
98011               }
98012             }).on(_t('area_fill.wireframe.key'), function toggleWireframe(d3_event) {
98013               d3_event.preventDefault();
98014               d3_event.stopPropagation();
98015               context.map().toggleWireframe();
98016             }).on(uiCmd('⌥' + _t('area_fill.wireframe.key')), function toggleOsmData(d3_event) {
98017               d3_event.preventDefault();
98018               d3_event.stopPropagation(); // Don't allow layer changes while drawing - #6584
98019
98020               var mode = context.mode();
98021               if (mode && /^draw/.test(mode.id)) return;
98022               var layer = context.layers().layer('osm');
98023
98024               if (layer) {
98025                 layer.enabled(!layer.enabled());
98026
98027                 if (!layer.enabled()) {
98028                   context.enter(modeBrowse(context));
98029                 }
98030               }
98031             }).on(_t('map_data.highlight_edits.key'), function toggleHighlightEdited(d3_event) {
98032               d3_event.preventDefault();
98033               context.map().toggleHighlightEdited();
98034             });
98035             context.on('enter.editor', function (entered) {
98036               container.classed('mode-' + entered.id, true);
98037             }).on('exit.editor', function (exited) {
98038               container.classed('mode-' + exited.id, false);
98039             });
98040             context.enter(modeBrowse(context));
98041
98042             if (!_initCounter++) {
98043               if (!ui.hash.startWalkthrough) {
98044                 context.container().call(uiSplash(context)).call(uiRestore(context));
98045               }
98046
98047               context.container().call(ui.shortcuts);
98048             }
98049
98050             var osm = context.connection();
98051             var auth = uiLoading(context).message(_t.html('loading_auth')).blocking(true);
98052
98053             if (osm && auth) {
98054               osm.on('authLoading.ui', function () {
98055                 context.container().call(auth);
98056               }).on('authDone.ui', function () {
98057                 auth.close();
98058               });
98059             }
98060
98061             _initCounter++;
98062
98063             if (ui.hash.startWalkthrough) {
98064               ui.hash.startWalkthrough = false;
98065               context.container().call(uiIntro(context));
98066             }
98067
98068             function pan(d) {
98069               return function (d3_event) {
98070                 if (d3_event.shiftKey) return;
98071                 if (context.container().select('.combobox').size()) return;
98072                 d3_event.preventDefault();
98073                 context.map().pan(d, 100);
98074               };
98075             }
98076           }
98077
98078           var ui = {};
98079
98080           var _loadPromise; // renders the iD interface into the container node
98081
98082
98083           ui.ensureLoaded = function () {
98084             if (_loadPromise) return _loadPromise;
98085             return _loadPromise = Promise.all([// must have strings and presets before loading the UI
98086             _mainLocalizer.ensureLoaded(), _mainPresetIndex.ensureLoaded()]).then(function () {
98087               if (!context.container().empty()) render(context.container());
98088             })["catch"](function (err) {
98089               return console.error(err);
98090             }); // eslint-disable-line
98091           }; // `ui.restart()` will destroy and rebuild the entire iD interface,
98092           // for example to switch the locale while iD is running.
98093
98094
98095           ui.restart = function () {
98096             context.keybinding().clear();
98097             _loadPromise = null;
98098             context.container().selectAll('*').remove();
98099             ui.ensureLoaded();
98100           };
98101
98102           ui.lastPointerType = function () {
98103             return _lastPointerType;
98104           };
98105
98106           ui.svgDefs = svgDefs(context);
98107           ui.flash = uiFlash(context);
98108           ui.sidebar = uiSidebar(context);
98109           ui.photoviewer = uiPhotoviewer(context);
98110           ui.shortcuts = uiShortcuts(context);
98111
98112           ui.onResize = function (withPan) {
98113             var map = context.map(); // Recalc dimensions of map and sidebar.. (`true` = force recalc)
98114             // This will call `getBoundingClientRect` and trigger reflow,
98115             //  but the values will be cached for later use.
98116
98117             var mapDimensions = utilGetDimensions(context.container().select('.main-content'), true);
98118             utilGetDimensions(context.container().select('.sidebar'), true);
98119
98120             if (withPan !== undefined) {
98121               map.redrawEnable(false);
98122               map.pan(withPan);
98123               map.redrawEnable(true);
98124             }
98125
98126             map.dimensions(mapDimensions);
98127             ui.photoviewer.onMapResize(); // check if header or footer have overflowed
98128
98129             ui.checkOverflow('.top-toolbar');
98130             ui.checkOverflow('.map-footer-bar'); // Use outdated code so it works on Explorer
98131
98132             var resizeWindowEvent = document.createEvent('Event');
98133             resizeWindowEvent.initEvent('resizeWindow', true, true);
98134             document.dispatchEvent(resizeWindowEvent);
98135           }; // Call checkOverflow when resizing or whenever the contents change.
98136
98137
98138           ui.checkOverflow = function (selector, reset) {
98139             if (reset) {
98140               delete _needWidth[selector];
98141             }
98142
98143             var selection = context.container().select(selector);
98144             if (selection.empty()) return;
98145             var scrollWidth = selection.property('scrollWidth');
98146             var clientWidth = selection.property('clientWidth');
98147             var needed = _needWidth[selector] || scrollWidth;
98148
98149             if (scrollWidth > clientWidth) {
98150               // overflow happening
98151               selection.classed('narrow', true);
98152
98153               if (!_needWidth[selector]) {
98154                 _needWidth[selector] = scrollWidth;
98155               }
98156             } else if (scrollWidth >= needed) {
98157               selection.classed('narrow', false);
98158             }
98159           };
98160
98161           ui.togglePanes = function (showPane) {
98162             var hidePanes = context.container().selectAll('.map-pane.shown');
98163             var side = _mainLocalizer.textDirection() === 'ltr' ? 'right' : 'left';
98164             hidePanes.classed('shown', false).classed('hide', true);
98165             context.container().selectAll('.map-pane-control button').classed('active', false);
98166
98167             if (showPane) {
98168               hidePanes.classed('shown', false).classed('hide', true).style(side, '-500px');
98169               context.container().selectAll('.' + showPane.attr('pane') + '-control button').classed('active', true);
98170               showPane.classed('shown', true).classed('hide', false);
98171
98172               if (hidePanes.empty()) {
98173                 showPane.style(side, '-500px').transition().duration(200).style(side, '0px');
98174               } else {
98175                 showPane.style(side, '0px');
98176               }
98177             } else {
98178               hidePanes.classed('shown', true).classed('hide', false).style(side, '0px').transition().duration(200).style(side, '-500px').on('end', function () {
98179                 select(this).classed('shown', false).classed('hide', true);
98180               });
98181             }
98182           };
98183
98184           var _editMenu = uiEditMenu(context);
98185
98186           ui.editMenu = function () {
98187             return _editMenu;
98188           };
98189
98190           ui.showEditMenu = function (anchorPoint, triggerType, operations) {
98191             // remove any displayed menu
98192             ui.closeEditMenu();
98193             if (!operations && context.mode().operations) operations = context.mode().operations();
98194             if (!operations || !operations.length) return; // disable menu if in wide selection, for example
98195
98196             if (!context.map().editableDataEnabled()) return;
98197             var surfaceNode = context.surface().node();
98198
98199             if (surfaceNode.focus) {
98200               // FF doesn't support it
98201               // focus the surface or else clicking off the menu may not trigger modeBrowse
98202               surfaceNode.focus();
98203             }
98204
98205             operations.forEach(function (operation) {
98206               if (operation.point) operation.point(anchorPoint);
98207             });
98208
98209             _editMenu.anchorLoc(anchorPoint).triggerType(triggerType).operations(operations); // render the menu
98210
98211
98212             context.map().supersurface.call(_editMenu);
98213           };
98214
98215           ui.closeEditMenu = function () {
98216             // remove any existing menu no matter how it was added
98217             context.map().supersurface.select('.edit-menu').remove();
98218           };
98219
98220           var _saveLoading = select(null);
98221
98222           context.uploader().on('saveStarted.ui', function () {
98223             _saveLoading = uiLoading(context).message(_t.html('save.uploading')).blocking(true);
98224             context.container().call(_saveLoading); // block input during upload
98225           }).on('saveEnded.ui', function () {
98226             _saveLoading.close();
98227
98228             _saveLoading = select(null);
98229           });
98230           return ui;
98231         }
98232
98233         function coreContext() {
98234           var _this = this;
98235
98236           var dispatch$1 = dispatch('enter', 'exit', 'change');
98237           var context = utilRebind({}, dispatch$1, 'on');
98238
98239           var _deferred = new Set();
98240
98241           context.version = '2.19.4';
98242           context.privacyVersion = '20200407'; // iD will alter the hash so cache the parameters intended to setup the session
98243
98244           context.initialHashParams = window.location.hash ? utilStringQs(window.location.hash) : {};
98245           context.isFirstSession = !corePreferences('sawSplash') && !corePreferences('sawPrivacyVersion');
98246           /* Changeset */
98247           // An osmChangeset object. Not loaded until needed.
98248
98249           context.changeset = null;
98250           var _defaultChangesetComment = context.initialHashParams.comment;
98251           var _defaultChangesetSource = context.initialHashParams.source;
98252           var _defaultChangesetHashtags = context.initialHashParams.hashtags;
98253
98254           context.defaultChangesetComment = function (val) {
98255             if (!arguments.length) return _defaultChangesetComment;
98256             _defaultChangesetComment = val;
98257             return context;
98258           };
98259
98260           context.defaultChangesetSource = function (val) {
98261             if (!arguments.length) return _defaultChangesetSource;
98262             _defaultChangesetSource = val;
98263             return context;
98264           };
98265
98266           context.defaultChangesetHashtags = function (val) {
98267             if (!arguments.length) return _defaultChangesetHashtags;
98268             _defaultChangesetHashtags = val;
98269             return context;
98270           };
98271           /* Document title */
98272
98273           /* (typically shown as the label for the browser window/tab) */
98274           // If true, iD will update the title based on what the user is doing
98275
98276
98277           var _setsDocumentTitle = true;
98278
98279           context.setsDocumentTitle = function (val) {
98280             if (!arguments.length) return _setsDocumentTitle;
98281             _setsDocumentTitle = val;
98282             return context;
98283           }; // The part of the title that is always the same
98284
98285
98286           var _documentTitleBase = document.title;
98287
98288           context.documentTitleBase = function (val) {
98289             if (!arguments.length) return _documentTitleBase;
98290             _documentTitleBase = val;
98291             return context;
98292           };
98293           /* User interface and keybinding */
98294
98295
98296           var _ui;
98297
98298           context.ui = function () {
98299             return _ui;
98300           };
98301
98302           context.lastPointerType = function () {
98303             return _ui.lastPointerType();
98304           };
98305
98306           var _keybinding = utilKeybinding('context');
98307
98308           context.keybinding = function () {
98309             return _keybinding;
98310           };
98311
98312           select(document).call(_keybinding);
98313           /* Straight accessors. Avoid using these if you can. */
98314           // Instantiate the connection here because it doesn't require passing in
98315           // `context` and it's needed for pre-init calls like `preauth`
98316
98317           var _connection = services.osm;
98318
98319           var _history;
98320
98321           var _validator;
98322
98323           var _uploader;
98324
98325           context.connection = function () {
98326             return _connection;
98327           };
98328
98329           context.history = function () {
98330             return _history;
98331           };
98332
98333           context.validator = function () {
98334             return _validator;
98335           };
98336
98337           context.uploader = function () {
98338             return _uploader;
98339           };
98340           /* Connection */
98341
98342
98343           context.preauth = function (options) {
98344             if (_connection) {
98345               _connection["switch"](options);
98346             }
98347
98348             return context;
98349           };
98350           /* connection options for source switcher (optional) */
98351
98352
98353           var _apiConnections;
98354
98355           context.apiConnections = function (val) {
98356             if (!arguments.length) return _apiConnections;
98357             _apiConnections = val;
98358             return context;
98359           }; // A string or array or locale codes to prefer over the browser's settings
98360
98361
98362           context.locale = function (locale) {
98363             if (!arguments.length) return _mainLocalizer.localeCode();
98364             _mainLocalizer.preferredLocaleCodes(locale);
98365             return context;
98366           };
98367
98368           function afterLoad(cid, callback) {
98369             return function (err, result) {
98370               if (err) {
98371                 // 400 Bad Request, 401 Unauthorized, 403 Forbidden..
98372                 if (err.status === 400 || err.status === 401 || err.status === 403) {
98373                   if (_connection) {
98374                     _connection.logout();
98375                   }
98376                 }
98377
98378                 if (typeof callback === 'function') {
98379                   callback(err);
98380                 }
98381
98382                 return;
98383               } else if (_connection && _connection.getConnectionId() !== cid) {
98384                 if (typeof callback === 'function') {
98385                   callback({
98386                     message: 'Connection Switched',
98387                     status: -1
98388                   });
98389                 }
98390
98391                 return;
98392               } else {
98393                 _history.merge(result.data, result.extent);
98394
98395                 if (typeof callback === 'function') {
98396                   callback(err, result);
98397                 }
98398
98399                 return;
98400               }
98401             };
98402           }
98403
98404           context.loadTiles = function (projection, callback) {
98405             var handle = window.requestIdleCallback(function () {
98406               _deferred["delete"](handle);
98407
98408               if (_connection && context.editableDataEnabled()) {
98409                 var cid = _connection.getConnectionId();
98410
98411                 _connection.loadTiles(projection, afterLoad(cid, callback));
98412               }
98413             });
98414
98415             _deferred.add(handle);
98416           };
98417
98418           context.loadTileAtLoc = function (loc, callback) {
98419             var handle = window.requestIdleCallback(function () {
98420               _deferred["delete"](handle);
98421
98422               if (_connection && context.editableDataEnabled()) {
98423                 var cid = _connection.getConnectionId();
98424
98425                 _connection.loadTileAtLoc(loc, afterLoad(cid, callback));
98426               }
98427             });
98428
98429             _deferred.add(handle);
98430           };
98431
98432           context.loadEntity = function (entityID, callback) {
98433             if (_connection) {
98434               var cid = _connection.getConnectionId();
98435
98436               _connection.loadEntity(entityID, afterLoad(cid, callback));
98437             }
98438           };
98439
98440           context.zoomToEntity = function (entityID, zoomTo) {
98441             if (zoomTo !== false) {
98442               context.loadEntity(entityID, function (err, result) {
98443                 if (err) return;
98444                 var entity = result.data.find(function (e) {
98445                   return e.id === entityID;
98446                 });
98447
98448                 if (entity) {
98449                   _map.zoomTo(entity);
98450                 }
98451               });
98452             }
98453
98454             _map.on('drawn.zoomToEntity', function () {
98455               if (!context.hasEntity(entityID)) return;
98456
98457               _map.on('drawn.zoomToEntity', null);
98458
98459               context.on('enter.zoomToEntity', null);
98460               context.enter(modeSelect(context, [entityID]));
98461             });
98462
98463             context.on('enter.zoomToEntity', function () {
98464               if (_mode.id !== 'browse') {
98465                 _map.on('drawn.zoomToEntity', null);
98466
98467                 context.on('enter.zoomToEntity', null);
98468               }
98469             });
98470           };
98471
98472           var _minEditableZoom = 16;
98473
98474           context.minEditableZoom = function (val) {
98475             if (!arguments.length) return _minEditableZoom;
98476             _minEditableZoom = val;
98477
98478             if (_connection) {
98479               _connection.tileZoom(val);
98480             }
98481
98482             return context;
98483           }; // String length limits in Unicode characters, not JavaScript UTF-16 code units
98484
98485
98486           context.maxCharsForTagKey = function () {
98487             return 255;
98488           };
98489
98490           context.maxCharsForTagValue = function () {
98491             return 255;
98492           };
98493
98494           context.maxCharsForRelationRole = function () {
98495             return 255;
98496           };
98497
98498           function cleanOsmString(val, maxChars) {
98499             // be lenient with input
98500             if (val === undefined || val === null) {
98501               val = '';
98502             } else {
98503               val = val.toString();
98504             } // remove whitespace
98505
98506
98507             val = val.trim(); // use the canonical form of the string
98508
98509             if (val.normalize) val = val.normalize('NFC'); // trim to the number of allowed characters
98510
98511             return utilUnicodeCharsTruncated(val, maxChars);
98512           }
98513
98514           context.cleanTagKey = function (val) {
98515             return cleanOsmString(val, context.maxCharsForTagKey());
98516           };
98517
98518           context.cleanTagValue = function (val) {
98519             return cleanOsmString(val, context.maxCharsForTagValue());
98520           };
98521
98522           context.cleanRelationRole = function (val) {
98523             return cleanOsmString(val, context.maxCharsForRelationRole());
98524           };
98525           /* History */
98526
98527
98528           var _inIntro = false;
98529
98530           context.inIntro = function (val) {
98531             if (!arguments.length) return _inIntro;
98532             _inIntro = val;
98533             return context;
98534           }; // Immediately save the user's history to localstorage, if possible
98535           // This is called someteimes, but also on the `window.onbeforeunload` handler
98536
98537
98538           context.save = function () {
98539             // no history save, no message onbeforeunload
98540             if (_inIntro || context.container().select('.modal').size()) return;
98541             var canSave;
98542
98543             if (_mode && _mode.id === 'save') {
98544               canSave = false; // Attempt to prevent user from creating duplicate changes - see #5200
98545
98546               if (services.osm && services.osm.isChangesetInflight()) {
98547                 _history.clearSaved();
98548
98549                 return;
98550               }
98551             } else {
98552               canSave = context.selectedIDs().every(function (id) {
98553                 var entity = context.hasEntity(id);
98554                 return entity && !entity.isDegenerate();
98555               });
98556             }
98557
98558             if (canSave) {
98559               _history.save();
98560             }
98561
98562             if (_history.hasChanges()) {
98563               return _t('save.unsaved_changes');
98564             }
98565           }; // Debounce save, since it's a synchronous localStorage write,
98566           // and history changes can happen frequently (e.g. when dragging).
98567
98568
98569           context.debouncedSave = debounce(context.save, 350);
98570
98571           function withDebouncedSave(fn) {
98572             return function () {
98573               var result = fn.apply(_history, arguments);
98574               context.debouncedSave();
98575               return result;
98576             };
98577           }
98578           /* Graph */
98579
98580
98581           context.hasEntity = function (id) {
98582             return _history.graph().hasEntity(id);
98583           };
98584
98585           context.entity = function (id) {
98586             return _history.graph().entity(id);
98587           };
98588           /* Modes */
98589
98590
98591           var _mode;
98592
98593           context.mode = function () {
98594             return _mode;
98595           };
98596
98597           context.enter = function (newMode) {
98598             if (_mode) {
98599               _mode.exit();
98600
98601               dispatch$1.call('exit', _this, _mode);
98602             }
98603
98604             _mode = newMode;
98605
98606             _mode.enter();
98607
98608             dispatch$1.call('enter', _this, _mode);
98609           };
98610
98611           context.selectedIDs = function () {
98612             return _mode && _mode.selectedIDs && _mode.selectedIDs() || [];
98613           };
98614
98615           context.activeID = function () {
98616             return _mode && _mode.activeID && _mode.activeID();
98617           };
98618
98619           var _selectedNoteID;
98620
98621           context.selectedNoteID = function (noteID) {
98622             if (!arguments.length) return _selectedNoteID;
98623             _selectedNoteID = noteID;
98624             return context;
98625           }; // NOTE: Don't change the name of this until UI v3 is merged
98626
98627
98628           var _selectedErrorID;
98629
98630           context.selectedErrorID = function (errorID) {
98631             if (!arguments.length) return _selectedErrorID;
98632             _selectedErrorID = errorID;
98633             return context;
98634           };
98635           /* Behaviors */
98636
98637
98638           context.install = function (behavior) {
98639             return context.surface().call(behavior);
98640           };
98641
98642           context.uninstall = function (behavior) {
98643             return context.surface().call(behavior.off);
98644           };
98645           /* Copy/Paste */
98646
98647
98648           var _copyGraph;
98649
98650           context.copyGraph = function () {
98651             return _copyGraph;
98652           };
98653
98654           var _copyIDs = [];
98655
98656           context.copyIDs = function (val) {
98657             if (!arguments.length) return _copyIDs;
98658             _copyIDs = val;
98659             _copyGraph = _history.graph();
98660             return context;
98661           };
98662
98663           var _copyLonLat;
98664
98665           context.copyLonLat = function (val) {
98666             if (!arguments.length) return _copyLonLat;
98667             _copyLonLat = val;
98668             return context;
98669           };
98670           /* Background */
98671
98672
98673           var _background;
98674
98675           context.background = function () {
98676             return _background;
98677           };
98678           /* Features */
98679
98680
98681           var _features;
98682
98683           context.features = function () {
98684             return _features;
98685           };
98686
98687           context.hasHiddenConnections = function (id) {
98688             var graph = _history.graph();
98689
98690             var entity = graph.entity(id);
98691             return _features.hasHiddenConnections(entity, graph);
98692           };
98693           /* Photos */
98694
98695
98696           var _photos;
98697
98698           context.photos = function () {
98699             return _photos;
98700           };
98701           /* Map */
98702
98703
98704           var _map;
98705
98706           context.map = function () {
98707             return _map;
98708           };
98709
98710           context.layers = function () {
98711             return _map.layers();
98712           };
98713
98714           context.surface = function () {
98715             return _map.surface;
98716           };
98717
98718           context.editableDataEnabled = function () {
98719             return _map.editableDataEnabled();
98720           };
98721
98722           context.surfaceRect = function () {
98723             return _map.surface.node().getBoundingClientRect();
98724           };
98725
98726           context.editable = function () {
98727             // don't allow editing during save
98728             var mode = context.mode();
98729             if (!mode || mode.id === 'save') return false;
98730             return _map.editableDataEnabled();
98731           };
98732           /* Debug */
98733
98734
98735           var _debugFlags = {
98736             tile: false,
98737             // tile boundaries
98738             collision: false,
98739             // label collision bounding boxes
98740             imagery: false,
98741             // imagery bounding polygons
98742             target: false,
98743             // touch targets
98744             downloaded: false // downloaded data from osm
98745
98746           };
98747
98748           context.debugFlags = function () {
98749             return _debugFlags;
98750           };
98751
98752           context.getDebug = function (flag) {
98753             return flag && _debugFlags[flag];
98754           };
98755
98756           context.setDebug = function (flag, val) {
98757             if (arguments.length === 1) val = true;
98758             _debugFlags[flag] = val;
98759             dispatch$1.call('change');
98760             return context;
98761           };
98762           /* Container */
98763
98764
98765           var _container = select(null);
98766
98767           context.container = function (val) {
98768             if (!arguments.length) return _container;
98769             _container = val;
98770
98771             _container.classed('ideditor', true);
98772
98773             return context;
98774           };
98775
98776           context.containerNode = function (val) {
98777             if (!arguments.length) return context.container().node();
98778             context.container(select(val));
98779             return context;
98780           };
98781
98782           var _embed;
98783
98784           context.embed = function (val) {
98785             if (!arguments.length) return _embed;
98786             _embed = val;
98787             return context;
98788           };
98789           /* Assets */
98790
98791
98792           var _assetPath = '';
98793
98794           context.assetPath = function (val) {
98795             if (!arguments.length) return _assetPath;
98796             _assetPath = val;
98797             _mainFileFetcher.assetPath(val);
98798             return context;
98799           };
98800
98801           var _assetMap = {};
98802
98803           context.assetMap = function (val) {
98804             if (!arguments.length) return _assetMap;
98805             _assetMap = val;
98806             _mainFileFetcher.assetMap(val);
98807             return context;
98808           };
98809
98810           context.asset = function (val) {
98811             if (/^http(s)?:\/\//i.test(val)) return val;
98812             var filename = _assetPath + val;
98813             return _assetMap[filename] || filename;
98814           };
98815
98816           context.imagePath = function (val) {
98817             return context.asset("img/".concat(val));
98818           };
98819           /* reset (aka flush) */
98820
98821
98822           context.reset = context.flush = function () {
98823             context.debouncedSave.cancel();
98824             Array.from(_deferred).forEach(function (handle) {
98825               window.cancelIdleCallback(handle);
98826
98827               _deferred["delete"](handle);
98828             });
98829             Object.values(services).forEach(function (service) {
98830               if (service && typeof service.reset === 'function') {
98831                 service.reset(context);
98832               }
98833             });
98834             context.changeset = null;
98835
98836             _validator.reset();
98837
98838             _features.reset();
98839
98840             _history.reset();
98841
98842             _uploader.reset(); // don't leave stale state in the inspector
98843
98844
98845             context.container().select('.inspector-wrap *').remove();
98846             return context;
98847           };
98848           /* Projections */
98849
98850
98851           context.projection = geoRawMercator();
98852           context.curtainProjection = geoRawMercator();
98853           /* Init */
98854
98855           context.init = function () {
98856             instantiateInternal();
98857             initializeDependents();
98858             return context; // Load variables and properties. No property of `context` should be accessed
98859             // until this is complete since load statuses are indeterminate. The order
98860             // of instantiation shouldn't matter.
98861
98862             function instantiateInternal() {
98863               _history = coreHistory(context);
98864               context.graph = _history.graph;
98865               context.pauseChangeDispatch = _history.pauseChangeDispatch;
98866               context.resumeChangeDispatch = _history.resumeChangeDispatch;
98867               context.perform = withDebouncedSave(_history.perform);
98868               context.replace = withDebouncedSave(_history.replace);
98869               context.pop = withDebouncedSave(_history.pop);
98870               context.overwrite = withDebouncedSave(_history.overwrite);
98871               context.undo = withDebouncedSave(_history.undo);
98872               context.redo = withDebouncedSave(_history.redo);
98873               _validator = coreValidator(context);
98874               _uploader = coreUploader(context);
98875               _background = rendererBackground(context);
98876               _features = rendererFeatures(context);
98877               _map = rendererMap(context);
98878               _photos = rendererPhotos(context);
98879               _ui = uiInit(context);
98880             } // Set up objects that might need to access properties of `context`. The order
98881             // might matter if dependents make calls to each other. Be wary of async calls.
98882
98883
98884             function initializeDependents() {
98885               if (context.initialHashParams.presets) {
98886                 _mainPresetIndex.addablePresetIDs(new Set(context.initialHashParams.presets.split(',')));
98887               }
98888
98889               if (context.initialHashParams.locale) {
98890                 _mainLocalizer.preferredLocaleCodes(context.initialHashParams.locale);
98891               } // kick off some async work
98892
98893
98894               _mainLocalizer.ensureLoaded();
98895
98896               _background.ensureLoaded();
98897
98898               _mainPresetIndex.ensureLoaded();
98899               Object.values(services).forEach(function (service) {
98900                 if (service && typeof service.init === 'function') {
98901                   service.init();
98902                 }
98903               });
98904
98905               _map.init();
98906
98907               _validator.init();
98908
98909               _features.init();
98910
98911               if (services.maprules && context.initialHashParams.maprules) {
98912                 d3_json(context.initialHashParams.maprules).then(function (mapcss) {
98913                   services.maprules.init();
98914                   mapcss.forEach(function (mapcssSelector) {
98915                     return services.maprules.addRule(mapcssSelector);
98916                   });
98917                 })["catch"](function () {
98918                   /* ignore */
98919                 });
98920               } // if the container isn't available, e.g. when testing, don't load the UI
98921
98922
98923               if (!context.container().empty()) {
98924                 _ui.ensureLoaded().then(function () {
98925                   _photos.init();
98926                 });
98927               }
98928             }
98929           };
98930
98931           return context;
98932         }
98933
98934         // This is only done in testing because of the performance penalty.
98935
98936         var debug = false; // Reexport just what our tests use, see #4379
98937         var d3 = {
98938           dispatch: dispatch,
98939           geoMercator: mercator,
98940           geoProjection: projection,
98941           polygonArea: d3_polygonArea,
98942           polygonCentroid: d3_polygonCentroid,
98943           select: select,
98944           selectAll: selectAll,
98945           timerFlush: timerFlush
98946         };
98947
98948         var iD = /*#__PURE__*/Object.freeze({
98949                 __proto__: null,
98950                 debug: debug,
98951                 d3: d3,
98952                 actionAddEntity: actionAddEntity,
98953                 actionAddMember: actionAddMember,
98954                 actionAddMidpoint: actionAddMidpoint,
98955                 actionAddVertex: actionAddVertex,
98956                 actionChangeMember: actionChangeMember,
98957                 actionChangePreset: actionChangePreset,
98958                 actionChangeTags: actionChangeTags,
98959                 actionCircularize: actionCircularize,
98960                 actionConnect: actionConnect,
98961                 actionCopyEntities: actionCopyEntities,
98962                 actionDeleteMember: actionDeleteMember,
98963                 actionDeleteMultiple: actionDeleteMultiple,
98964                 actionDeleteNode: actionDeleteNode,
98965                 actionDeleteRelation: actionDeleteRelation,
98966                 actionDeleteWay: actionDeleteWay,
98967                 actionDiscardTags: actionDiscardTags,
98968                 actionDisconnect: actionDisconnect,
98969                 actionExtract: actionExtract,
98970                 actionJoin: actionJoin,
98971                 actionMerge: actionMerge,
98972                 actionMergeNodes: actionMergeNodes,
98973                 actionMergePolygon: actionMergePolygon,
98974                 actionMergeRemoteChanges: actionMergeRemoteChanges,
98975                 actionMove: actionMove,
98976                 actionMoveMember: actionMoveMember,
98977                 actionMoveNode: actionMoveNode,
98978                 actionNoop: actionNoop,
98979                 actionOrthogonalize: actionOrthogonalize,
98980                 actionRestrictTurn: actionRestrictTurn,
98981                 actionReverse: actionReverse,
98982                 actionRevert: actionRevert,
98983                 actionRotate: actionRotate,
98984                 actionScale: actionScale,
98985                 actionSplit: actionSplit,
98986                 actionStraightenNodes: actionStraightenNodes,
98987                 actionStraightenWay: actionStraightenWay,
98988                 actionUnrestrictTurn: actionUnrestrictTurn,
98989                 actionReflect: actionReflect,
98990                 actionUpgradeTags: actionUpgradeTags,
98991                 behaviorAddWay: behaviorAddWay,
98992                 behaviorBreathe: behaviorBreathe,
98993                 behaviorDrag: behaviorDrag,
98994                 behaviorDrawWay: behaviorDrawWay,
98995                 behaviorDraw: behaviorDraw,
98996                 behaviorEdit: behaviorEdit,
98997                 behaviorHash: behaviorHash,
98998                 behaviorHover: behaviorHover,
98999                 behaviorLasso: behaviorLasso,
99000                 behaviorOperation: behaviorOperation,
99001                 behaviorPaste: behaviorPaste,
99002                 behaviorSelect: behaviorSelect,
99003                 coreContext: coreContext,
99004                 coreFileFetcher: coreFileFetcher,
99005                 fileFetcher: _mainFileFetcher,
99006                 coreDifference: coreDifference,
99007                 coreGraph: coreGraph,
99008                 coreHistory: coreHistory,
99009                 coreLocalizer: coreLocalizer,
99010                 t: _t,
99011                 localizer: _mainLocalizer,
99012                 prefs: corePreferences,
99013                 coreTree: coreTree,
99014                 coreUploader: coreUploader,
99015                 coreValidator: coreValidator,
99016                 geoExtent: geoExtent,
99017                 geoLatToMeters: geoLatToMeters,
99018                 geoLonToMeters: geoLonToMeters,
99019                 geoMetersToLat: geoMetersToLat,
99020                 geoMetersToLon: geoMetersToLon,
99021                 geoMetersToOffset: geoMetersToOffset,
99022                 geoOffsetToMeters: geoOffsetToMeters,
99023                 geoScaleToZoom: geoScaleToZoom,
99024                 geoSphericalClosestNode: geoSphericalClosestNode,
99025                 geoSphericalDistance: geoSphericalDistance,
99026                 geoZoomToScale: geoZoomToScale,
99027                 geoAngle: geoAngle,
99028                 geoChooseEdge: geoChooseEdge,
99029                 geoEdgeEqual: geoEdgeEqual,
99030                 geoGetSmallestSurroundingRectangle: geoGetSmallestSurroundingRectangle,
99031                 geoHasLineIntersections: geoHasLineIntersections,
99032                 geoHasSelfIntersections: geoHasSelfIntersections,
99033                 geoRotate: geoRotate,
99034                 geoLineIntersection: geoLineIntersection,
99035                 geoPathHasIntersections: geoPathHasIntersections,
99036                 geoPathIntersections: geoPathIntersections,
99037                 geoPathLength: geoPathLength,
99038                 geoPointInPolygon: geoPointInPolygon,
99039                 geoPolygonContainsPolygon: geoPolygonContainsPolygon,
99040                 geoPolygonIntersectsPolygon: geoPolygonIntersectsPolygon,
99041                 geoViewportEdge: geoViewportEdge,
99042                 geoRawMercator: geoRawMercator,
99043                 geoVecAdd: geoVecAdd,
99044                 geoVecAngle: geoVecAngle,
99045                 geoVecCross: geoVecCross,
99046                 geoVecDot: geoVecDot,
99047                 geoVecEqual: geoVecEqual,
99048                 geoVecFloor: geoVecFloor,
99049                 geoVecInterp: geoVecInterp,
99050                 geoVecLength: geoVecLength,
99051                 geoVecLengthSquare: geoVecLengthSquare,
99052                 geoVecNormalize: geoVecNormalize,
99053                 geoVecNormalizedDot: geoVecNormalizedDot,
99054                 geoVecProject: geoVecProject,
99055                 geoVecSubtract: geoVecSubtract,
99056                 geoVecScale: geoVecScale,
99057                 geoOrthoNormalizedDotProduct: geoOrthoNormalizedDotProduct,
99058                 geoOrthoCalcScore: geoOrthoCalcScore,
99059                 geoOrthoMaxOffsetAngle: geoOrthoMaxOffsetAngle,
99060                 geoOrthoCanOrthogonalize: geoOrthoCanOrthogonalize,
99061                 modeAddArea: modeAddArea,
99062                 modeAddLine: modeAddLine,
99063                 modeAddPoint: modeAddPoint,
99064                 modeAddNote: modeAddNote,
99065                 modeBrowse: modeBrowse,
99066                 modeDragNode: modeDragNode,
99067                 modeDragNote: modeDragNote,
99068                 modeDrawArea: modeDrawArea,
99069                 modeDrawLine: modeDrawLine,
99070                 modeMove: modeMove,
99071                 modeRotate: modeRotate,
99072                 modeSave: modeSave,
99073                 modeSelect: modeSelect,
99074                 modeSelectData: modeSelectData,
99075                 modeSelectError: modeSelectError,
99076                 modeSelectNote: modeSelectNote,
99077                 operationCircularize: operationCircularize,
99078                 operationContinue: operationContinue,
99079                 operationCopy: operationCopy,
99080                 operationDelete: operationDelete,
99081                 operationDisconnect: operationDisconnect,
99082                 operationDowngrade: operationDowngrade,
99083                 operationExtract: operationExtract,
99084                 operationMerge: operationMerge,
99085                 operationMove: operationMove,
99086                 operationOrthogonalize: operationOrthogonalize,
99087                 operationPaste: operationPaste,
99088                 operationReflectShort: operationReflectShort,
99089                 operationReflectLong: operationReflectLong,
99090                 operationReverse: operationReverse,
99091                 operationRotate: operationRotate,
99092                 operationSplit: operationSplit,
99093                 operationStraighten: operationStraighten,
99094                 osmChangeset: osmChangeset,
99095                 osmEntity: osmEntity,
99096                 osmNode: osmNode,
99097                 osmNote: osmNote,
99098                 osmRelation: osmRelation,
99099                 osmWay: osmWay,
99100                 QAItem: QAItem,
99101                 osmIntersection: osmIntersection,
99102                 osmTurn: osmTurn,
99103                 osmInferRestriction: osmInferRestriction,
99104                 osmLanes: osmLanes,
99105                 osmOldMultipolygonOuterMemberOfRelation: osmOldMultipolygonOuterMemberOfRelation,
99106                 osmIsOldMultipolygonOuterMember: osmIsOldMultipolygonOuterMember,
99107                 osmOldMultipolygonOuterMember: osmOldMultipolygonOuterMember,
99108                 osmJoinWays: osmJoinWays,
99109                 get osmAreaKeys () { return osmAreaKeys; },
99110                 osmSetAreaKeys: osmSetAreaKeys,
99111                 osmTagSuggestingArea: osmTagSuggestingArea,
99112                 get osmPointTags () { return osmPointTags; },
99113                 osmSetPointTags: osmSetPointTags,
99114                 get osmVertexTags () { return osmVertexTags; },
99115                 osmSetVertexTags: osmSetVertexTags,
99116                 osmNodeGeometriesForTags: osmNodeGeometriesForTags,
99117                 osmOneWayTags: osmOneWayTags,
99118                 osmPavedTags: osmPavedTags,
99119                 osmIsInterestingTag: osmIsInterestingTag,
99120                 osmRoutableHighwayTagValues: osmRoutableHighwayTagValues,
99121                 osmFlowingWaterwayTagValues: osmFlowingWaterwayTagValues,
99122                 osmRailwayTrackTagValues: osmRailwayTrackTagValues,
99123                 presetCategory: presetCategory,
99124                 presetCollection: presetCollection,
99125                 presetField: presetField,
99126                 presetPreset: presetPreset,
99127                 presetManager: _mainPresetIndex,
99128                 presetIndex: presetIndex,
99129                 rendererBackgroundSource: rendererBackgroundSource,
99130                 rendererBackground: rendererBackground,
99131                 rendererFeatures: rendererFeatures,
99132                 rendererMap: rendererMap,
99133                 rendererPhotos: rendererPhotos,
99134                 rendererTileLayer: rendererTileLayer,
99135                 services: services,
99136                 serviceKeepRight: serviceKeepRight,
99137                 serviceImproveOSM: serviceImproveOSM,
99138                 serviceOsmose: serviceOsmose,
99139                 serviceMapillary: serviceMapillary,
99140                 serviceMapRules: serviceMapRules,
99141                 serviceNominatim: serviceNominatim,
99142                 serviceOpenstreetcam: serviceOpenstreetcam,
99143                 serviceOsm: serviceOsm,
99144                 serviceOsmWikibase: serviceOsmWikibase,
99145                 serviceStreetside: serviceStreetside,
99146                 serviceTaginfo: serviceTaginfo,
99147                 serviceVectorTile: serviceVectorTile,
99148                 serviceWikidata: serviceWikidata,
99149                 serviceWikipedia: serviceWikipedia,
99150                 svgAreas: svgAreas,
99151                 svgData: svgData,
99152                 svgDebug: svgDebug,
99153                 svgDefs: svgDefs,
99154                 svgKeepRight: svgKeepRight,
99155                 svgIcon: svgIcon,
99156                 svgGeolocate: svgGeolocate,
99157                 svgLabels: svgLabels,
99158                 svgLayers: svgLayers,
99159                 svgLines: svgLines,
99160                 svgMapillaryImages: svgMapillaryImages,
99161                 svgMapillarySigns: svgMapillarySigns,
99162                 svgMidpoints: svgMidpoints,
99163                 svgNotes: svgNotes,
99164                 svgMarkerSegments: svgMarkerSegments,
99165                 svgOpenstreetcamImages: svgOpenstreetcamImages,
99166                 svgOsm: svgOsm,
99167                 svgPassiveVertex: svgPassiveVertex,
99168                 svgPath: svgPath,
99169                 svgPointTransform: svgPointTransform,
99170                 svgPoints: svgPoints,
99171                 svgRelationMemberTags: svgRelationMemberTags,
99172                 svgSegmentWay: svgSegmentWay,
99173                 svgStreetside: svgStreetside,
99174                 svgTagClasses: svgTagClasses,
99175                 svgTagPattern: svgTagPattern,
99176                 svgTouch: svgTouch,
99177                 svgTurns: svgTurns,
99178                 svgVertices: svgVertices,
99179                 uiFieldDefaultCheck: uiFieldCheck,
99180                 uiFieldOnewayCheck: uiFieldCheck,
99181                 uiFieldCheck: uiFieldCheck,
99182                 uiFieldManyCombo: uiFieldCombo,
99183                 uiFieldMultiCombo: uiFieldCombo,
99184                 uiFieldNetworkCombo: uiFieldCombo,
99185                 uiFieldSemiCombo: uiFieldCombo,
99186                 uiFieldTypeCombo: uiFieldCombo,
99187                 uiFieldCombo: uiFieldCombo,
99188                 uiFieldUrl: uiFieldText,
99189                 uiFieldIdentifier: uiFieldText,
99190                 uiFieldNumber: uiFieldText,
99191                 uiFieldTel: uiFieldText,
99192                 uiFieldEmail: uiFieldText,
99193                 uiFieldText: uiFieldText,
99194                 uiFieldAccess: uiFieldAccess,
99195                 uiFieldAddress: uiFieldAddress,
99196                 uiFieldCycleway: uiFieldCycleway,
99197                 uiFieldLanes: uiFieldLanes,
99198                 uiFieldLocalized: uiFieldLocalized,
99199                 uiFieldMaxspeed: uiFieldMaxspeed,
99200                 uiFieldStructureRadio: uiFieldRadio,
99201                 uiFieldRadio: uiFieldRadio,
99202                 uiFieldRestrictions: uiFieldRestrictions,
99203                 uiFieldTextarea: uiFieldTextarea,
99204                 uiFieldWikidata: uiFieldWikidata,
99205                 uiFieldWikipedia: uiFieldWikipedia,
99206                 uiFields: uiFields,
99207                 uiIntro: uiIntro,
99208                 uiPanelBackground: uiPanelBackground,
99209                 uiPanelHistory: uiPanelHistory,
99210                 uiPanelLocation: uiPanelLocation,
99211                 uiPanelMeasurement: uiPanelMeasurement,
99212                 uiInfoPanels: uiInfoPanels,
99213                 uiPaneBackground: uiPaneBackground,
99214                 uiPaneHelp: uiPaneHelp,
99215                 uiPaneIssues: uiPaneIssues,
99216                 uiPaneMapData: uiPaneMapData,
99217                 uiPanePreferences: uiPanePreferences,
99218                 uiSectionBackgroundDisplayOptions: uiSectionBackgroundDisplayOptions,
99219                 uiSectionBackgroundList: uiSectionBackgroundList,
99220                 uiSectionBackgroundOffset: uiSectionBackgroundOffset,
99221                 uiSectionChanges: uiSectionChanges,
99222                 uiSectionDataLayers: uiSectionDataLayers,
99223                 uiSectionEntityIssues: uiSectionEntityIssues,
99224                 uiSectionFeatureType: uiSectionFeatureType,
99225                 uiSectionMapFeatures: uiSectionMapFeatures,
99226                 uiSectionMapStyleOptions: uiSectionMapStyleOptions,
99227                 uiSectionOverlayList: uiSectionOverlayList,
99228                 uiSectionPhotoOverlays: uiSectionPhotoOverlays,
99229                 uiSectionPresetFields: uiSectionPresetFields,
99230                 uiSectionPrivacy: uiSectionPrivacy,
99231                 uiSectionRawMemberEditor: uiSectionRawMemberEditor,
99232                 uiSectionRawMembershipEditor: uiSectionRawMembershipEditor,
99233                 uiSectionRawTagEditor: uiSectionRawTagEditor,
99234                 uiSectionSelectionList: uiSectionSelectionList,
99235                 uiSectionValidationIssues: uiSectionValidationIssues,
99236                 uiSectionValidationOptions: uiSectionValidationOptions,
99237                 uiSectionValidationRules: uiSectionValidationRules,
99238                 uiSectionValidationStatus: uiSectionValidationStatus,
99239                 uiSettingsCustomBackground: uiSettingsCustomBackground,
99240                 uiSettingsCustomData: uiSettingsCustomData,
99241                 uiInit: uiInit,
99242                 uiAccount: uiAccount,
99243                 uiAttribution: uiAttribution,
99244                 uiChangesetEditor: uiChangesetEditor,
99245                 uiCmd: uiCmd,
99246                 uiCombobox: uiCombobox,
99247                 uiCommit: uiCommit,
99248                 uiCommitWarnings: uiCommitWarnings,
99249                 uiConfirm: uiConfirm,
99250                 uiConflicts: uiConflicts,
99251                 uiContributors: uiContributors,
99252                 uiCurtain: uiCurtain,
99253                 uiDataEditor: uiDataEditor,
99254                 uiDataHeader: uiDataHeader,
99255                 uiDisclosure: uiDisclosure,
99256                 uiEditMenu: uiEditMenu,
99257                 uiEntityEditor: uiEntityEditor,
99258                 uiFeatureInfo: uiFeatureInfo,
99259                 uiFeatureList: uiFeatureList,
99260                 uiField: uiField,
99261                 uiFieldHelp: uiFieldHelp,
99262                 uiFlash: uiFlash,
99263                 uiFormFields: uiFormFields,
99264                 uiFullScreen: uiFullScreen,
99265                 uiGeolocate: uiGeolocate,
99266                 uiImproveOsmComments: uiImproveOsmComments,
99267                 uiImproveOsmDetails: uiImproveOsmDetails,
99268                 uiImproveOsmEditor: uiImproveOsmEditor,
99269                 uiImproveOsmHeader: uiImproveOsmHeader,
99270                 uiInfo: uiInfo,
99271                 uiInspector: uiInspector,
99272                 uiIssuesInfo: uiIssuesInfo,
99273                 uiKeepRightDetails: uiKeepRightDetails,
99274                 uiKeepRightEditor: uiKeepRightEditor,
99275                 uiKeepRightHeader: uiKeepRightHeader,
99276                 uiLasso: uiLasso,
99277                 uiLoading: uiLoading,
99278                 uiMapInMap: uiMapInMap,
99279                 uiModal: uiModal,
99280                 uiNotice: uiNotice,
99281                 uiNoteComments: uiNoteComments,
99282                 uiNoteEditor: uiNoteEditor,
99283                 uiNoteHeader: uiNoteHeader,
99284                 uiNoteReport: uiNoteReport,
99285                 uiPopover: uiPopover,
99286                 uiPresetIcon: uiPresetIcon,
99287                 uiPresetList: uiPresetList,
99288                 uiRestore: uiRestore,
99289                 uiScale: uiScale,
99290                 uiSidebar: uiSidebar,
99291                 uiSourceSwitch: uiSourceSwitch,
99292                 uiSpinner: uiSpinner,
99293                 uiSplash: uiSplash,
99294                 uiStatus: uiStatus,
99295                 uiSuccess: uiSuccess,
99296                 uiTagReference: uiTagReference,
99297                 uiToggle: uiToggle,
99298                 uiTooltip: uiTooltip,
99299                 uiVersion: uiVersion,
99300                 uiViewOnOSM: uiViewOnOSM,
99301                 uiViewOnKeepRight: uiViewOnKeepRight,
99302                 uiZoom: uiZoom,
99303                 utilAesEncrypt: utilAesEncrypt,
99304                 utilAesDecrypt: utilAesDecrypt,
99305                 utilArrayChunk: utilArrayChunk,
99306                 utilArrayDifference: utilArrayDifference,
99307                 utilArrayFlatten: utilArrayFlatten,
99308                 utilArrayGroupBy: utilArrayGroupBy,
99309                 utilArrayIdentical: utilArrayIdentical,
99310                 utilArrayIntersection: utilArrayIntersection,
99311                 utilArrayUnion: utilArrayUnion,
99312                 utilArrayUniq: utilArrayUniq,
99313                 utilArrayUniqBy: utilArrayUniqBy,
99314                 utilAsyncMap: utilAsyncMap,
99315                 utilCleanTags: utilCleanTags,
99316                 utilCombinedTags: utilCombinedTags,
99317                 utilDeepMemberSelector: utilDeepMemberSelector,
99318                 utilDetect: utilDetect,
99319                 utilDisplayName: utilDisplayName,
99320                 utilDisplayNameForPath: utilDisplayNameForPath,
99321                 utilDisplayType: utilDisplayType,
99322                 utilDisplayLabel: utilDisplayLabel,
99323                 utilEntityRoot: utilEntityRoot,
99324                 utilEditDistance: utilEditDistance,
99325                 utilEntitySelector: utilEntitySelector,
99326                 utilEntityOrMemberSelector: utilEntityOrMemberSelector,
99327                 utilEntityOrDeepMemberSelector: utilEntityOrDeepMemberSelector,
99328                 utilFastMouse: utilFastMouse,
99329                 utilFunctor: utilFunctor,
99330                 utilGetAllNodes: utilGetAllNodes,
99331                 utilGetSetValue: utilGetSetValue,
99332                 utilHashcode: utilHashcode,
99333                 utilHighlightEntities: utilHighlightEntities,
99334                 utilKeybinding: utilKeybinding,
99335                 utilNoAuto: utilNoAuto,
99336                 utilObjectOmit: utilObjectOmit,
99337                 utilPrefixCSSProperty: utilPrefixCSSProperty,
99338                 utilPrefixDOMProperty: utilPrefixDOMProperty,
99339                 utilQsString: utilQsString,
99340                 utilRebind: utilRebind,
99341                 utilSafeClassName: utilSafeClassName,
99342                 utilSetTransform: utilSetTransform,
99343                 utilSessionMutex: utilSessionMutex,
99344                 utilStringQs: utilStringQs,
99345                 utilTagDiff: utilTagDiff,
99346                 utilTagText: utilTagText,
99347                 utilTiler: utilTiler,
99348                 utilTotalExtent: utilTotalExtent,
99349                 utilTriggerEvent: utilTriggerEvent,
99350                 utilUnicodeCharsCount: utilUnicodeCharsCount,
99351                 utilUnicodeCharsTruncated: utilUnicodeCharsTruncated,
99352                 utilUniqueDomId: utilUniqueDomId,
99353                 utilWrap: utilWrap,
99354                 validationAlmostJunction: validationAlmostJunction,
99355                 validationCloseNodes: validationCloseNodes,
99356                 validationCrossingWays: validationCrossingWays,
99357                 validationDisconnectedWay: validationDisconnectedWay,
99358                 validationFormatting: validationFormatting,
99359                 validationHelpRequest: validationHelpRequest,
99360                 validationImpossibleOneway: validationImpossibleOneway,
99361                 validationIncompatibleSource: validationIncompatibleSource,
99362                 validationMaprules: validationMaprules,
99363                 validationMismatchedGeometry: validationMismatchedGeometry,
99364                 validationMissingRole: validationMissingRole,
99365                 validationMissingTag: validationMissingTag,
99366                 validationOutdatedTags: validationOutdatedTags,
99367                 validationPrivateData: validationPrivateData,
99368                 validationSuspiciousName: validationSuspiciousName,
99369                 validationUnsquareWay: validationUnsquareWay
99370         });
99371
99372         window.requestIdleCallback = window.requestIdleCallback || function (cb) {
99373           var start = Date.now();
99374           return window.requestAnimationFrame(function () {
99375             cb({
99376               didTimeout: false,
99377               timeRemaining: function timeRemaining() {
99378                 return Math.max(0, 50 - (Date.now() - start));
99379               }
99380             });
99381           });
99382         };
99383
99384         window.cancelIdleCallback = window.cancelIdleCallback || function (id) {
99385           window.cancelAnimationFrame(id);
99386         };
99387         window.iD = iD;
99388
99389 }());